17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5490ed22dSyz147064 * Common Development and Distribution License (the "License").
6490ed22dSyz147064 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21843e1988Sjohnlev
227c478bd9Sstevel@tonic-gate /*
230591ddd0SPrakash Jalan * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2484de666eSRyan Zezeski * Copyright 2020 Joyent, Inc.
253bc4925dSGarrett D'Amore * Copyright 2015 Garrett D'Amore <garrett@damore.org>
26d77e6e0fSPaul Winder * Copyright 2020 RackTop Systems, Inc.
27*67cac09cSKyle Simpson * Copyright 2024 Oxide Computer Company
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * MAC Services Module
32da14cebeSEric Cheng *
33da14cebeSEric Cheng * The GLDv3 framework locking - The MAC layer
34da14cebeSEric Cheng * --------------------------------------------
35da14cebeSEric Cheng *
36da14cebeSEric Cheng * The MAC layer is central to the GLD framework and can provide the locking
37da14cebeSEric Cheng * framework needed for itself and for the use of MAC clients. MAC end points
38da14cebeSEric Cheng * are fairly disjoint and don't share a lot of state. So a coarse grained
39da14cebeSEric Cheng * multi-threading scheme is to single thread all create/modify/delete or set
40da14cebeSEric Cheng * type of control operations on a per mac end point while allowing data threads
41da14cebeSEric Cheng * concurrently.
42da14cebeSEric Cheng *
43da14cebeSEric Cheng * Control operations (set) that modify a mac end point are always serialized on
44da14cebeSEric Cheng * a per mac end point basis, We have at most 1 such thread per mac end point
45da14cebeSEric Cheng * at a time.
46da14cebeSEric Cheng *
47da14cebeSEric Cheng * All other operations that are not serialized are essentially multi-threaded.
48da14cebeSEric Cheng * For example a control operation (get) like getting statistics which may not
49da14cebeSEric Cheng * care about reading values atomically or data threads sending or receiving
50da14cebeSEric Cheng * data. Mostly these type of operations don't modify the control state. Any
51da14cebeSEric Cheng * state these operations care about are protected using traditional locks.
52da14cebeSEric Cheng *
53da14cebeSEric Cheng * The perimeter only serializes serial operations. It does not imply there
54da14cebeSEric Cheng * aren't any other concurrent operations. However a serialized operation may
55da14cebeSEric Cheng * sometimes need to make sure it is the only thread. In this case it needs
56da14cebeSEric Cheng * to use reference counting mechanisms to cv_wait until any current data
57da14cebeSEric Cheng * threads are done.
58da14cebeSEric Cheng *
59da14cebeSEric Cheng * The mac layer itself does not hold any locks across a call to another layer.
60da14cebeSEric Cheng * The perimeter is however held across a down call to the driver to make the
61da14cebeSEric Cheng * whole control operation atomic with respect to other control operations.
62da14cebeSEric Cheng * Also the data path and get type control operations may proceed concurrently.
63da14cebeSEric Cheng * These operations synchronize with the single serial operation on a given mac
64da14cebeSEric Cheng * end point using regular locks. The perimeter ensures that conflicting
65da14cebeSEric Cheng * operations like say a mac_multicast_add and a mac_multicast_remove on the
66da14cebeSEric Cheng * same mac end point don't interfere with each other and also ensures that the
67da14cebeSEric Cheng * changes in the mac layer and the call to the underlying driver to say add a
68da14cebeSEric Cheng * multicast address are done atomically without interference from a thread
69da14cebeSEric Cheng * trying to delete the same address.
70da14cebeSEric Cheng *
71da14cebeSEric Cheng * For example, consider
72da14cebeSEric Cheng * mac_multicst_add()
73da14cebeSEric Cheng * {
74da14cebeSEric Cheng * mac_perimeter_enter(); serialize all control operations
75da14cebeSEric Cheng *
76da14cebeSEric Cheng * grab list lock protect against access by data threads
77da14cebeSEric Cheng * add to list
78da14cebeSEric Cheng * drop list lock
79da14cebeSEric Cheng *
80da14cebeSEric Cheng * call driver's mi_multicst
81da14cebeSEric Cheng *
82da14cebeSEric Cheng * mac_perimeter_exit();
83da14cebeSEric Cheng * }
84da14cebeSEric Cheng *
85da14cebeSEric Cheng * To lessen the number of serialization locks and simplify the lock hierarchy,
86da14cebeSEric Cheng * we serialize all the control operations on a per mac end point by using a
87da14cebeSEric Cheng * single serialization lock called the perimeter. We allow recursive entry into
88da14cebeSEric Cheng * the perimeter to facilitate use of this mechanism by both the mac client and
89da14cebeSEric Cheng * the MAC layer itself.
90da14cebeSEric Cheng *
91da14cebeSEric Cheng * MAC client means an entity that does an operation on a mac handle
92da14cebeSEric Cheng * obtained from a mac_open/mac_client_open. Similarly MAC driver means
93da14cebeSEric Cheng * an entity that does an operation on a mac handle obtained from a
94da14cebeSEric Cheng * mac_register. An entity could be both client and driver but on different
95da14cebeSEric Cheng * handles eg. aggr. and should only make the corresponding mac interface calls
96da14cebeSEric Cheng * i.e. mac driver interface or mac client interface as appropriate for that
97da14cebeSEric Cheng * mac handle.
98da14cebeSEric Cheng *
99da14cebeSEric Cheng * General rules.
100da14cebeSEric Cheng * -------------
101da14cebeSEric Cheng *
102da14cebeSEric Cheng * R1. The lock order of upcall threads is natually opposite to downcall
103da14cebeSEric Cheng * threads. Hence upcalls must not hold any locks across layers for fear of
104da14cebeSEric Cheng * recursive lock enter and lock order violation. This applies to all layers.
105da14cebeSEric Cheng *
106da14cebeSEric Cheng * R2. The perimeter is just another lock. Since it is held in the down
107da14cebeSEric Cheng * direction, acquiring the perimeter in an upcall is prohibited as it would
108da14cebeSEric Cheng * cause a deadlock. This applies to all layers.
109da14cebeSEric Cheng *
110da14cebeSEric Cheng * Note that upcalls that need to grab the mac perimeter (for example
111da14cebeSEric Cheng * mac_notify upcalls) can still achieve that by posting the request to a
112da14cebeSEric Cheng * thread, which can then grab all the required perimeters and locks in the
113da14cebeSEric Cheng * right global order. Note that in the above example the mac layer iself
114da14cebeSEric Cheng * won't grab the mac perimeter in the mac_notify upcall, instead the upcall
115da14cebeSEric Cheng * to the client must do that. Please see the aggr code for an example.
116da14cebeSEric Cheng *
117da14cebeSEric Cheng * MAC client rules
118da14cebeSEric Cheng * ----------------
119da14cebeSEric Cheng *
120da14cebeSEric Cheng * R3. A MAC client may use the MAC provided perimeter facility to serialize
121da14cebeSEric Cheng * control operations on a per mac end point. It does this by by acquring
122da14cebeSEric Cheng * and holding the perimeter across a sequence of calls to the mac layer.
123da14cebeSEric Cheng * This ensures atomicity across the entire block of mac calls. In this
124da14cebeSEric Cheng * model the MAC client must not hold any client locks across the calls to
125da14cebeSEric Cheng * the mac layer. This model is the preferred solution.
126da14cebeSEric Cheng *
127da14cebeSEric Cheng * R4. However if a MAC client has a lot of global state across all mac end
128da14cebeSEric Cheng * points the per mac end point serialization may not be sufficient. In this
129da14cebeSEric Cheng * case the client may choose to use global locks or use its own serialization.
130da14cebeSEric Cheng * To avoid deadlocks, these client layer locks held across the mac calls
131da14cebeSEric Cheng * in the control path must never be acquired by the data path for the reason
132da14cebeSEric Cheng * mentioned below.
133da14cebeSEric Cheng *
134da14cebeSEric Cheng * (Assume that a control operation that holds a client lock blocks in the
135da14cebeSEric Cheng * mac layer waiting for upcall reference counts to drop to zero. If an upcall
136da14cebeSEric Cheng * data thread that holds this reference count, tries to acquire the same
137da14cebeSEric Cheng * client lock subsequently it will deadlock).
138da14cebeSEric Cheng *
139da14cebeSEric Cheng * A MAC client may follow either the R3 model or the R4 model, but can't
140da14cebeSEric Cheng * mix both. In the former, the hierarchy is Perim -> client locks, but in
141da14cebeSEric Cheng * the latter it is client locks -> Perim.
142da14cebeSEric Cheng *
143da14cebeSEric Cheng * R5. MAC clients must make MAC calls (excluding data calls) in a cv_wait'able
144da14cebeSEric Cheng * context since they may block while trying to acquire the perimeter.
145da14cebeSEric Cheng * In addition some calls may block waiting for upcall refcnts to come down to
146da14cebeSEric Cheng * zero.
147da14cebeSEric Cheng *
148da14cebeSEric Cheng * R6. MAC clients must make sure that they are single threaded and all threads
149da14cebeSEric Cheng * from the top (in particular data threads) have finished before calling
150da14cebeSEric Cheng * mac_client_close. The MAC framework does not track the number of client
151da14cebeSEric Cheng * threads using the mac client handle. Also mac clients must make sure
152da14cebeSEric Cheng * they have undone all the control operations before calling mac_client_close.
153da14cebeSEric Cheng * For example mac_unicast_remove/mac_multicast_remove to undo the corresponding
154da14cebeSEric Cheng * mac_unicast_add/mac_multicast_add.
155da14cebeSEric Cheng *
156da14cebeSEric Cheng * MAC framework rules
157da14cebeSEric Cheng * -------------------
158da14cebeSEric Cheng *
159da14cebeSEric Cheng * R7. The mac layer itself must not hold any mac layer locks (except the mac
160da14cebeSEric Cheng * perimeter) across a call to any other layer from the mac layer. The call to
161da14cebeSEric Cheng * any other layer could be via mi_* entry points, classifier entry points into
162da14cebeSEric Cheng * the driver or via upcall pointers into layers above. The mac perimeter may
163da14cebeSEric Cheng * be acquired or held only in the down direction, for e.g. when calling into
164da14cebeSEric Cheng * a mi_* driver enty point to provide atomicity of the operation.
165da14cebeSEric Cheng *
166da14cebeSEric Cheng * R8. Since it is not guaranteed (see R14) that drivers won't hold locks across
167da14cebeSEric Cheng * mac driver interfaces, the MAC layer must provide a cut out for control
168da14cebeSEric Cheng * interfaces like upcall notifications and start them in a separate thread.
169da14cebeSEric Cheng *
170da14cebeSEric Cheng * R9. Note that locking order also implies a plumbing order. For example
171da14cebeSEric Cheng * VNICs are allowed to be created over aggrs, but not vice-versa. An attempt
172da14cebeSEric Cheng * to plumb in any other order must be failed at mac_open time, otherwise it
173da14cebeSEric Cheng * could lead to deadlocks due to inverse locking order.
174da14cebeSEric Cheng *
175da14cebeSEric Cheng * R10. MAC driver interfaces must not block since the driver could call them
176da14cebeSEric Cheng * in interrupt context.
177da14cebeSEric Cheng *
178da14cebeSEric Cheng * R11. Walkers must preferably not hold any locks while calling walker
179da14cebeSEric Cheng * callbacks. Instead these can operate on reference counts. In simple
180da14cebeSEric Cheng * callbacks it may be ok to hold a lock and call the callbacks, but this is
181da14cebeSEric Cheng * harder to maintain in the general case of arbitrary callbacks.
182da14cebeSEric Cheng *
183da14cebeSEric Cheng * R12. The MAC layer must protect upcall notification callbacks using reference
184da14cebeSEric Cheng * counts rather than holding locks across the callbacks.
185da14cebeSEric Cheng *
186da14cebeSEric Cheng * R13. Given the variety of drivers, it is preferable if the MAC layer can make
187da14cebeSEric Cheng * sure that any pointers (such as mac ring pointers) it passes to the driver
188da14cebeSEric Cheng * remain valid until mac unregister time. Currently the mac layer achieves
189da14cebeSEric Cheng * this by using generation numbers for rings and freeing the mac rings only
190da14cebeSEric Cheng * at unregister time. The MAC layer must provide a layer of indirection and
191da14cebeSEric Cheng * must not expose underlying driver rings or driver data structures/pointers
192da14cebeSEric Cheng * directly to MAC clients.
193da14cebeSEric Cheng *
194da14cebeSEric Cheng * MAC driver rules
195da14cebeSEric Cheng * ----------------
196da14cebeSEric Cheng *
197da14cebeSEric Cheng * R14. It would be preferable if MAC drivers don't hold any locks across any
198da14cebeSEric Cheng * mac call. However at a minimum they must not hold any locks across data
199da14cebeSEric Cheng * upcalls. They must also make sure that all references to mac data structures
200da14cebeSEric Cheng * are cleaned up and that it is single threaded at mac_unregister time.
201da14cebeSEric Cheng *
202da14cebeSEric Cheng * R15. MAC driver interfaces don't block and so the action may be done
203da14cebeSEric Cheng * asynchronously in a separate thread as for example handling notifications.
204da14cebeSEric Cheng * The driver must not assume that the action is complete when the call
205da14cebeSEric Cheng * returns.
206da14cebeSEric Cheng *
207da14cebeSEric Cheng * R16. Drivers must maintain a generation number per Rx ring, and pass it
208da14cebeSEric Cheng * back to mac_rx_ring(); They are expected to increment the generation
209da14cebeSEric Cheng * number whenever the ring's stop routine is invoked.
210da14cebeSEric Cheng * See comments in mac_rx_ring();
211da14cebeSEric Cheng *
212da14cebeSEric Cheng * R17 Similarly mi_stop is another synchronization point and the driver must
213da14cebeSEric Cheng * ensure that all upcalls are done and there won't be any future upcall
214da14cebeSEric Cheng * before returning from mi_stop.
215da14cebeSEric Cheng *
216da14cebeSEric Cheng * R18. The driver may assume that all set/modify control operations via
217da14cebeSEric Cheng * the mi_* entry points are single threaded on a per mac end point.
218da14cebeSEric Cheng *
219da14cebeSEric Cheng * Lock and Perimeter hierarchy scenarios
220da14cebeSEric Cheng * ---------------------------------------
221da14cebeSEric Cheng *
222da14cebeSEric Cheng * i_mac_impl_lock -> mi_rw_lock -> srs_lock -> s_ring_lock[i_mac_tx_srs_notify]
223da14cebeSEric Cheng *
224da14cebeSEric Cheng * ft_lock -> fe_lock [mac_flow_lookup]
225da14cebeSEric Cheng *
226da14cebeSEric Cheng * mi_rw_lock -> fe_lock [mac_bcast_send]
227da14cebeSEric Cheng *
228da14cebeSEric Cheng * srs_lock -> mac_bw_lock [mac_rx_srs_drain_bw]
229da14cebeSEric Cheng *
230da14cebeSEric Cheng * cpu_lock -> mac_srs_g_lock -> srs_lock -> s_ring_lock [mac_walk_srs_and_bind]
231da14cebeSEric Cheng *
232da14cebeSEric Cheng * i_dls_devnet_lock -> mac layer locks [dls_devnet_rename]
233da14cebeSEric Cheng *
234da14cebeSEric Cheng * Perimeters are ordered P1 -> P2 -> P3 from top to bottom in order of mac
235da14cebeSEric Cheng * client to driver. In the case of clients that explictly use the mac provided
236da14cebeSEric Cheng * perimeter mechanism for its serialization, the hierarchy is
237da14cebeSEric Cheng * Perimeter -> mac layer locks, since the client never holds any locks across
238da14cebeSEric Cheng * the mac calls. In the case of clients that use its own locks the hierarchy
239da14cebeSEric Cheng * is Client locks -> Mac Perim -> Mac layer locks. The client never explicitly
240da14cebeSEric Cheng * calls mac_perim_enter/exit in this case.
241da14cebeSEric Cheng *
242da14cebeSEric Cheng * Subflow creation rules
243da14cebeSEric Cheng * ---------------------------
244da14cebeSEric Cheng * o In case of a user specified cpulist present on underlying link and flows,
245da14cebeSEric Cheng * the flows cpulist must be a subset of the underlying link.
246da14cebeSEric Cheng * o In case of a user specified fanout mode present on link and flow, the
247da14cebeSEric Cheng * subflow fanout count has to be less than or equal to that of the
248da14cebeSEric Cheng * underlying link. The cpu-bindings for the subflows will be a subset of
249da14cebeSEric Cheng * the underlying link.
250da14cebeSEric Cheng * o In case if no cpulist specified on both underlying link and flow, the
251da14cebeSEric Cheng * underlying link relies on a MAC tunable to provide out of box fanout.
252da14cebeSEric Cheng * The subflow will have no cpulist (the subflow will be unbound)
253da14cebeSEric Cheng * o In case if no cpulist is specified on the underlying link, a subflow can
254da14cebeSEric Cheng * carry either a user-specified cpulist or fanout count. The cpu-bindings
255da14cebeSEric Cheng * for the subflow will not adhere to restriction that they need to be subset
256da14cebeSEric Cheng * of the underlying link.
257da14cebeSEric Cheng * o In case where the underlying link is carrying either a user specified
258da14cebeSEric Cheng * cpulist or fanout mode and for a unspecified subflow, the subflow will be
259da14cebeSEric Cheng * created unbound.
260da14cebeSEric Cheng * o While creating unbound subflows, bandwidth mode changes attempt to
261da14cebeSEric Cheng * figure a right fanout count. In such cases the fanout count will override
262da14cebeSEric Cheng * the unbound cpu-binding behavior.
263da14cebeSEric Cheng * o In addition to this, while cycling between flow and link properties, we
264da14cebeSEric Cheng * impose a restriction that if a link property has a subflow with
265da14cebeSEric Cheng * user-specified attributes, we will not allow changing the link property.
266da14cebeSEric Cheng * The administrator needs to reset all the user specified properties for the
267da14cebeSEric Cheng * subflows before attempting a link property change.
268da14cebeSEric Cheng * Some of the above rules can be overridden by specifying additional command
269da14cebeSEric Cheng * line options while creating or modifying link or subflow properties.
270bc44a933SRobert Mustacchi *
271bc44a933SRobert Mustacchi * Datapath
272bc44a933SRobert Mustacchi * --------
273bc44a933SRobert Mustacchi *
274bc44a933SRobert Mustacchi * For information on the datapath, the world of soft rings, hardware rings, how
275bc44a933SRobert Mustacchi * it is structured, and the path of an mblk_t between a driver and a mac
276bc44a933SRobert Mustacchi * client, see mac_sched.c.
2777c478bd9Sstevel@tonic-gate */
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate #include <sys/types.h>
2807c478bd9Sstevel@tonic-gate #include <sys/conf.h>
281d62bc4baSyz147064 #include <sys/id_space.h>
2828de9d095Syz147064 #include <sys/esunddi.h>
2837c478bd9Sstevel@tonic-gate #include <sys/stat.h>
284d62bc4baSyz147064 #include <sys/mkdev.h>
2857c478bd9Sstevel@tonic-gate #include <sys/stream.h>
2867c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
2877c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
2887c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
289c228408bSMichael Lim #include <sys/list.h>
290210db224Sericheng #include <sys/modhash.h>
291da14cebeSEric Cheng #include <sys/mac_provider.h>
292da14cebeSEric Cheng #include <sys/mac_client_impl.h>
293da14cebeSEric Cheng #include <sys/mac_soft_ring.h>
2940dc2366fSVenugopal Iyer #include <sys/mac_stat.h>
2957c478bd9Sstevel@tonic-gate #include <sys/mac_impl.h>
296da14cebeSEric Cheng #include <sys/mac.h>
297da14cebeSEric Cheng #include <sys/dls.h>
298210db224Sericheng #include <sys/dld.h>
299ba2e4443Sseb #include <sys/modctl.h>
300f4b3ec61Sdh155122 #include <sys/fs/dv_node.h>
3010487e2c9Sgd78059 #include <sys/thread.h>
3020487e2c9Sgd78059 #include <sys/proc.h>
3030487e2c9Sgd78059 #include <sys/callb.h>
3040487e2c9Sgd78059 #include <sys/cpuvar.h>
305bd7f69f6Sseb #include <sys/atomic.h>
306da14cebeSEric Cheng #include <sys/bitmap.h>
3071f8aaf0dSethindra #include <sys/sdt.h>
308da14cebeSEric Cheng #include <sys/mac_flow.h>
309da14cebeSEric Cheng #include <sys/ddi_intr_impl.h>
310da14cebeSEric Cheng #include <sys/disp.h>
311da14cebeSEric Cheng #include <sys/sdt.h>
312da14cebeSEric Cheng #include <sys/vnic.h>
313da14cebeSEric Cheng #include <sys/vnic_impl.h>
314da14cebeSEric Cheng #include <sys/vlan.h>
315da14cebeSEric Cheng #include <inet/ip.h>
316da14cebeSEric Cheng #include <inet/ip6.h>
317da14cebeSEric Cheng #include <sys/exacct.h>
318da14cebeSEric Cheng #include <sys/exacct_impl.h>
319e7801d59Ssowmini #include <inet/nd.h>
3204045d941Ssowmini #include <sys/ethernet.h>
3210dc2366fSVenugopal Iyer #include <sys/pool.h>
3220dc2366fSVenugopal Iyer #include <sys/pool_pset.h>
3230dc2366fSVenugopal Iyer #include <sys/cpupart.h>
3240dc2366fSVenugopal Iyer #include <inet/wifi_ioctl.h>
3250dc2366fSVenugopal Iyer #include <net/wpa.h>
326dd72704bSRobert Mustacchi #include <sys/mac_ether.h>
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */
3297c478bd9Sstevel@tonic-gate
330da14cebeSEric Cheng kmem_cache_t *i_mac_impl_cachep;
331da14cebeSEric Cheng mod_hash_t *i_mac_impl_hash;
332210db224Sericheng krwlock_t i_mac_impl_lock;
333210db224Sericheng uint_t i_mac_impl_count;
334da14cebeSEric Cheng static kmem_cache_t *mac_ring_cache;
335d62bc4baSyz147064 static id_space_t *minor_ids;
336d62bc4baSyz147064 static uint32_t minor_count;
3370dc2366fSVenugopal Iyer static pool_event_cb_t mac_pool_event_reg;
3387c478bd9Sstevel@tonic-gate
339da14cebeSEric Cheng /*
340da14cebeSEric Cheng * Logging stuff. Perhaps mac_logging_interval could be broken into
341da14cebeSEric Cheng * mac_flow_log_interval and mac_link_log_interval if we want to be
342da14cebeSEric Cheng * able to schedule them differently.
343da14cebeSEric Cheng */
344da14cebeSEric Cheng uint_t mac_logging_interval;
345da14cebeSEric Cheng boolean_t mac_flow_log_enable;
346da14cebeSEric Cheng boolean_t mac_link_log_enable;
347da14cebeSEric Cheng timeout_id_t mac_logging_timer;
348da14cebeSEric Cheng
349ba2e4443Sseb #define MACTYPE_KMODDIR "mac"
350ba2e4443Sseb #define MACTYPE_HASHSZ 67
351ba2e4443Sseb static mod_hash_t *i_mactype_hash;
352bd7f69f6Sseb /*
353bd7f69f6Sseb * i_mactype_lock synchronizes threads that obtain references to mactype_t
354bd7f69f6Sseb * structures through i_mactype_getplugin().
355bd7f69f6Sseb */
356bd7f69f6Sseb static kmutex_t i_mactype_lock;
357ba2e4443Sseb
3587c478bd9Sstevel@tonic-gate /*
359da14cebeSEric Cheng * mac_tx_percpu_cnt
360da14cebeSEric Cheng *
361da14cebeSEric Cheng * Number of per cpu locks per mac_client_impl_t. Used by the transmit side
362da14cebeSEric Cheng * in mac_tx to reduce lock contention. This is sized at boot time in mac_init.
363da14cebeSEric Cheng * mac_tx_percpu_cnt_max is settable in /etc/system and must be a power of 2.
364da14cebeSEric Cheng * Per cpu locks may be disabled by setting mac_tx_percpu_cnt_max to 1.
3657c478bd9Sstevel@tonic-gate */
366da14cebeSEric Cheng int mac_tx_percpu_cnt;
367da14cebeSEric Cheng int mac_tx_percpu_cnt_max = 128;
3687c478bd9Sstevel@tonic-gate
3694eaa4710SRishi Srivatsavai /*
3704eaa4710SRishi Srivatsavai * Call back functions for the bridge module. These are guaranteed to be valid
3714eaa4710SRishi Srivatsavai * when holding a reference on a link or when holding mip->mi_bridge_lock and
3724eaa4710SRishi Srivatsavai * mi_bridge_link is non-NULL.
3734eaa4710SRishi Srivatsavai */
3744eaa4710SRishi Srivatsavai mac_bridge_tx_t mac_bridge_tx_cb;
3754eaa4710SRishi Srivatsavai mac_bridge_rx_t mac_bridge_rx_cb;
3764eaa4710SRishi Srivatsavai mac_bridge_ref_t mac_bridge_ref_cb;
3774eaa4710SRishi Srivatsavai mac_bridge_ls_t mac_bridge_ls_cb;
3784eaa4710SRishi Srivatsavai
379da14cebeSEric Cheng static int i_mac_constructor(void *, void *, int);
380da14cebeSEric Cheng static void i_mac_destructor(void *, void *);
381da14cebeSEric Cheng static int i_mac_ring_ctor(void *, void *, int);
382da14cebeSEric Cheng static void i_mac_ring_dtor(void *, void *);
383*67cac09cSKyle Simpson static flow_entry_t *mac_rx_classify(mac_impl_t *, mac_resource_handle_t,
384*67cac09cSKyle Simpson mblk_t *);
385da14cebeSEric Cheng void mac_tx_client_flush(mac_client_impl_t *);
386da14cebeSEric Cheng void mac_tx_client_block(mac_client_impl_t *);
387da14cebeSEric Cheng static void mac_rx_ring_quiesce(mac_ring_t *, uint_t);
388da14cebeSEric Cheng static int mac_start_group_and_rings(mac_group_t *);
389da14cebeSEric Cheng static void mac_stop_group_and_rings(mac_group_t *);
3900dc2366fSVenugopal Iyer static void mac_pool_event_cb(pool_event_t, int, void *);
391ba2e4443Sseb
392c228408bSMichael Lim typedef struct netinfo_s {
393c228408bSMichael Lim list_node_t ni_link;
394c228408bSMichael Lim void *ni_record;
395c228408bSMichael Lim int ni_size;
396c228408bSMichael Lim int ni_type;
397c228408bSMichael Lim } netinfo_t;
398c228408bSMichael Lim
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * Module initialization functions.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate void
mac_init(void)4047c478bd9Sstevel@tonic-gate mac_init(void)
4057c478bd9Sstevel@tonic-gate {
406da14cebeSEric Cheng mac_tx_percpu_cnt = ((boot_max_ncpus == -1) ? max_ncpus :
407da14cebeSEric Cheng boot_max_ncpus);
408da14cebeSEric Cheng
409da14cebeSEric Cheng /* Upper bound is mac_tx_percpu_cnt_max */
410da14cebeSEric Cheng if (mac_tx_percpu_cnt > mac_tx_percpu_cnt_max)
411da14cebeSEric Cheng mac_tx_percpu_cnt = mac_tx_percpu_cnt_max;
412da14cebeSEric Cheng
413da14cebeSEric Cheng if (mac_tx_percpu_cnt < 1) {
414da14cebeSEric Cheng /* Someone set max_tx_percpu_cnt_max to 0 or less */
415da14cebeSEric Cheng mac_tx_percpu_cnt = 1;
416da14cebeSEric Cheng }
417da14cebeSEric Cheng
418da14cebeSEric Cheng ASSERT(mac_tx_percpu_cnt >= 1);
419da14cebeSEric Cheng mac_tx_percpu_cnt = (1 << highbit(mac_tx_percpu_cnt - 1));
420da14cebeSEric Cheng /*
421da14cebeSEric Cheng * Make it of the form 2**N - 1 in the range
422da14cebeSEric Cheng * [0 .. mac_tx_percpu_cnt_max - 1]
423da14cebeSEric Cheng */
424da14cebeSEric Cheng mac_tx_percpu_cnt--;
425da14cebeSEric Cheng
4267c478bd9Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
427ba2e4443Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
428ba2e4443Sseb NULL, NULL, NULL, 0);
4297c478bd9Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL);
4307c478bd9Sstevel@tonic-gate
431da14cebeSEric Cheng mac_ring_cache = kmem_cache_create("mac_ring_cache",
432da14cebeSEric Cheng sizeof (mac_ring_t), 0, i_mac_ring_ctor, i_mac_ring_dtor, NULL,
433da14cebeSEric Cheng NULL, NULL, 0);
434da14cebeSEric Cheng ASSERT(mac_ring_cache != NULL);
435843e1988Sjohnlev
436210db224Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
437210db224Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
438210db224Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
439210db224Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
440da14cebeSEric Cheng
441da14cebeSEric Cheng mac_flow_init();
442da14cebeSEric Cheng mac_soft_ring_init();
443da14cebeSEric Cheng mac_bcast_init();
444da14cebeSEric Cheng mac_client_init();
445da14cebeSEric Cheng
446210db224Sericheng i_mac_impl_count = 0;
447ba2e4443Sseb
448ba2e4443Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash",
449ba2e4443Sseb MACTYPE_HASHSZ,
450ba2e4443Sseb mod_hash_null_keydtor, mod_hash_null_valdtor,
451ba2e4443Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
452d62bc4baSyz147064
453d62bc4baSyz147064 /*
454d62bc4baSyz147064 * Allocate an id space to manage minor numbers. The range of the
45593a61d92SGarrett D'Amore * space will be from MAC_MAX_MINOR+1 to MAC_PRIVATE_MINOR-1. This
45693a61d92SGarrett D'Amore * leaves half of the 32-bit minors available for driver private use.
457d62bc4baSyz147064 */
45893a61d92SGarrett D'Amore minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1,
45993a61d92SGarrett D'Amore MAC_PRIVATE_MINOR-1);
460d62bc4baSyz147064 ASSERT(minor_ids != NULL);
461d62bc4baSyz147064 minor_count = 0;
462da14cebeSEric Cheng
463da14cebeSEric Cheng /* Let's default to 20 seconds */
464da14cebeSEric Cheng mac_logging_interval = 20;
465da14cebeSEric Cheng mac_flow_log_enable = B_FALSE;
466da14cebeSEric Cheng mac_link_log_enable = B_FALSE;
46784de666eSRyan Zezeski mac_logging_timer = NULL;
4680dc2366fSVenugopal Iyer
4690dc2366fSVenugopal Iyer /* Register to be notified of noteworthy pools events */
4700dc2366fSVenugopal Iyer mac_pool_event_reg.pec_func = mac_pool_event_cb;
4710dc2366fSVenugopal Iyer mac_pool_event_reg.pec_arg = NULL;
4720dc2366fSVenugopal Iyer pool_event_cb_register(&mac_pool_event_reg);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate int
mac_fini(void)4767c478bd9Sstevel@tonic-gate mac_fini(void)
4777c478bd9Sstevel@tonic-gate {
4780dc2366fSVenugopal Iyer
479d62bc4baSyz147064 if (i_mac_impl_count > 0 || minor_count > 0)
480210db224Sericheng return (EBUSY);
4817c478bd9Sstevel@tonic-gate
4820dc2366fSVenugopal Iyer pool_event_cb_unregister(&mac_pool_event_reg);
4830dc2366fSVenugopal Iyer
484d62bc4baSyz147064 id_space_destroy(minor_ids);
485da14cebeSEric Cheng mac_flow_fini();
486d62bc4baSyz147064
487210db224Sericheng mod_hash_destroy_hash(i_mac_impl_hash);
488210db224Sericheng rw_destroy(&i_mac_impl_lock);
4897c478bd9Sstevel@tonic-gate
490da14cebeSEric Cheng mac_client_fini();
491da14cebeSEric Cheng kmem_cache_destroy(mac_ring_cache);
492ba2e4443Sseb
493ba2e4443Sseb mod_hash_destroy_hash(i_mactype_hash);
494da14cebeSEric Cheng mac_soft_ring_finish();
4950dc2366fSVenugopal Iyer
4960dc2366fSVenugopal Iyer
4977c478bd9Sstevel@tonic-gate return (0);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate
500ee94b1c3SSebastien Roy /*
501ee94b1c3SSebastien Roy * Initialize a GLDv3 driver's device ops. A driver that manages its own ops
502ee94b1c3SSebastien Roy * (e.g. softmac) may pass in a NULL ops argument.
503ee94b1c3SSebastien Roy */
504da14cebeSEric Cheng void
mac_init_ops(struct dev_ops * ops,const char * name)505da14cebeSEric Cheng mac_init_ops(struct dev_ops *ops, const char *name)
506da14cebeSEric Cheng {
507ee94b1c3SSebastien Roy major_t major = ddi_name_to_major((char *)name);
508ee94b1c3SSebastien Roy
509ee94b1c3SSebastien Roy /*
510ee94b1c3SSebastien Roy * By returning on error below, we are not letting the driver continue
511ee94b1c3SSebastien Roy * in an undefined context. The mac_register() function will faill if
512ee94b1c3SSebastien Roy * DN_GLDV3_DRIVER isn't set.
513ee94b1c3SSebastien Roy */
514ee94b1c3SSebastien Roy if (major == DDI_MAJOR_T_NONE)
515ee94b1c3SSebastien Roy return;
516ee94b1c3SSebastien Roy LOCK_DEV_OPS(&devnamesp[major].dn_lock);
517ee94b1c3SSebastien Roy devnamesp[major].dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
518ee94b1c3SSebastien Roy UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
519ee94b1c3SSebastien Roy if (ops != NULL)
520da14cebeSEric Cheng dld_init_ops(ops, name);
521da14cebeSEric Cheng }
5227c478bd9Sstevel@tonic-gate
523da14cebeSEric Cheng void
mac_fini_ops(struct dev_ops * ops)524da14cebeSEric Cheng mac_fini_ops(struct dev_ops *ops)
525da14cebeSEric Cheng {
526da14cebeSEric Cheng dld_fini_ops(ops);
527da14cebeSEric Cheng }
528da14cebeSEric Cheng
529da14cebeSEric Cheng /*ARGSUSED*/
530d62bc4baSyz147064 static int
i_mac_constructor(void * buf,void * arg,int kmflag)531da14cebeSEric Cheng i_mac_constructor(void *buf, void *arg, int kmflag)
532da14cebeSEric Cheng {
533da14cebeSEric Cheng mac_impl_t *mip = buf;
534da14cebeSEric Cheng
535da14cebeSEric Cheng bzero(buf, sizeof (mac_impl_t));
536da14cebeSEric Cheng
537da14cebeSEric Cheng mip->mi_linkstate = LINK_STATE_UNKNOWN;
538da14cebeSEric Cheng
539da14cebeSEric Cheng rw_init(&mip->mi_rw_lock, NULL, RW_DRIVER, NULL);
540da14cebeSEric Cheng mutex_init(&mip->mi_notify_lock, NULL, MUTEX_DRIVER, NULL);
541da14cebeSEric Cheng mutex_init(&mip->mi_promisc_lock, NULL, MUTEX_DRIVER, NULL);
542da14cebeSEric Cheng mutex_init(&mip->mi_ring_lock, NULL, MUTEX_DEFAULT, NULL);
543da14cebeSEric Cheng
544da14cebeSEric Cheng mip->mi_notify_cb_info.mcbi_lockp = &mip->mi_notify_lock;
545da14cebeSEric Cheng cv_init(&mip->mi_notify_cb_info.mcbi_cv, NULL, CV_DRIVER, NULL);
546da14cebeSEric Cheng mip->mi_promisc_cb_info.mcbi_lockp = &mip->mi_promisc_lock;
547da14cebeSEric Cheng cv_init(&mip->mi_promisc_cb_info.mcbi_cv, NULL, CV_DRIVER, NULL);
5484eaa4710SRishi Srivatsavai
5494eaa4710SRishi Srivatsavai mutex_init(&mip->mi_bridge_lock, NULL, MUTEX_DEFAULT, NULL);
5504eaa4710SRishi Srivatsavai
551da14cebeSEric Cheng return (0);
552da14cebeSEric Cheng }
553da14cebeSEric Cheng
554da14cebeSEric Cheng /*ARGSUSED*/
555da14cebeSEric Cheng static void
i_mac_destructor(void * buf,void * arg)556da14cebeSEric Cheng i_mac_destructor(void *buf, void *arg)
557da14cebeSEric Cheng {
558da14cebeSEric Cheng mac_impl_t *mip = buf;
559da14cebeSEric Cheng mac_cb_info_t *mcbi;
560da14cebeSEric Cheng
561da14cebeSEric Cheng ASSERT(mip->mi_ref == 0);
562da14cebeSEric Cheng ASSERT(mip->mi_active == 0);
563da14cebeSEric Cheng ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
564da14cebeSEric Cheng ASSERT(mip->mi_devpromisc == 0);
565da14cebeSEric Cheng ASSERT(mip->mi_ksp == NULL);
566da14cebeSEric Cheng ASSERT(mip->mi_kstat_count == 0);
567da14cebeSEric Cheng ASSERT(mip->mi_nclients == 0);
568da14cebeSEric Cheng ASSERT(mip->mi_nactiveclients == 0);
569ae6aa22aSVenugopal Iyer ASSERT(mip->mi_single_active_client == NULL);
570da14cebeSEric Cheng ASSERT(mip->mi_state_flags == 0);
571da14cebeSEric Cheng ASSERT(mip->mi_factory_addr == NULL);
572da14cebeSEric Cheng ASSERT(mip->mi_factory_addr_num == 0);
573da14cebeSEric Cheng ASSERT(mip->mi_default_tx_ring == NULL);
574da14cebeSEric Cheng
575da14cebeSEric Cheng mcbi = &mip->mi_notify_cb_info;
576da14cebeSEric Cheng ASSERT(mcbi->mcbi_del_cnt == 0 && mcbi->mcbi_walker_cnt == 0);
577da14cebeSEric Cheng ASSERT(mip->mi_notify_bits == 0);
578da14cebeSEric Cheng ASSERT(mip->mi_notify_thread == NULL);
579da14cebeSEric Cheng ASSERT(mcbi->mcbi_lockp == &mip->mi_notify_lock);
580da14cebeSEric Cheng mcbi->mcbi_lockp = NULL;
581da14cebeSEric Cheng
582da14cebeSEric Cheng mcbi = &mip->mi_promisc_cb_info;
583da14cebeSEric Cheng ASSERT(mcbi->mcbi_del_cnt == 0 && mip->mi_promisc_list == NULL);
584da14cebeSEric Cheng ASSERT(mip->mi_promisc_list == NULL);
585da14cebeSEric Cheng ASSERT(mcbi->mcbi_lockp == &mip->mi_promisc_lock);
586da14cebeSEric Cheng mcbi->mcbi_lockp = NULL;
587da14cebeSEric Cheng
588da14cebeSEric Cheng ASSERT(mip->mi_bcast_ngrps == 0 && mip->mi_bcast_grp == NULL);
589da14cebeSEric Cheng ASSERT(mip->mi_perim_owner == NULL && mip->mi_perim_ocnt == 0);
590da14cebeSEric Cheng
591da14cebeSEric Cheng rw_destroy(&mip->mi_rw_lock);
592da14cebeSEric Cheng
593da14cebeSEric Cheng mutex_destroy(&mip->mi_promisc_lock);
594da14cebeSEric Cheng cv_destroy(&mip->mi_promisc_cb_info.mcbi_cv);
595da14cebeSEric Cheng mutex_destroy(&mip->mi_notify_lock);
596da14cebeSEric Cheng cv_destroy(&mip->mi_notify_cb_info.mcbi_cv);
597da14cebeSEric Cheng mutex_destroy(&mip->mi_ring_lock);
5984eaa4710SRishi Srivatsavai
5994eaa4710SRishi Srivatsavai ASSERT(mip->mi_bridge_link == NULL);
600da14cebeSEric Cheng }
601da14cebeSEric Cheng
602da14cebeSEric Cheng /* ARGSUSED */
603da14cebeSEric Cheng static int
i_mac_ring_ctor(void * buf,void * arg,int kmflag)604da14cebeSEric Cheng i_mac_ring_ctor(void *buf, void *arg, int kmflag)
605da14cebeSEric Cheng {
606da14cebeSEric Cheng mac_ring_t *ring = (mac_ring_t *)buf;
607da14cebeSEric Cheng
608da14cebeSEric Cheng bzero(ring, sizeof (mac_ring_t));
609da14cebeSEric Cheng cv_init(&ring->mr_cv, NULL, CV_DEFAULT, NULL);
610da14cebeSEric Cheng mutex_init(&ring->mr_lock, NULL, MUTEX_DEFAULT, NULL);
611da14cebeSEric Cheng ring->mr_state = MR_FREE;
612da14cebeSEric Cheng return (0);
613da14cebeSEric Cheng }
614da14cebeSEric Cheng
615da14cebeSEric Cheng /* ARGSUSED */
616da14cebeSEric Cheng static void
i_mac_ring_dtor(void * buf,void * arg)617da14cebeSEric Cheng i_mac_ring_dtor(void *buf, void *arg)
618da14cebeSEric Cheng {
619da14cebeSEric Cheng mac_ring_t *ring = (mac_ring_t *)buf;
620da14cebeSEric Cheng
621da14cebeSEric Cheng cv_destroy(&ring->mr_cv);
622da14cebeSEric Cheng mutex_destroy(&ring->mr_lock);
623da14cebeSEric Cheng }
624da14cebeSEric Cheng
625da14cebeSEric Cheng /*
626da14cebeSEric Cheng * Common functions to do mac callback addition and deletion. Currently this is
627da14cebeSEric Cheng * used by promisc callbacks and notify callbacks. List addition and deletion
628da14cebeSEric Cheng * need to take care of list walkers. List walkers in general, can't hold list
629da14cebeSEric Cheng * locks and make upcall callbacks due to potential lock order and recursive
630da14cebeSEric Cheng * reentry issues. Instead list walkers increment the list walker count to mark
631da14cebeSEric Cheng * the presence of a walker thread. Addition can be carefully done to ensure
632da14cebeSEric Cheng * that the list walker always sees either the old list or the new list.
633da14cebeSEric Cheng * However the deletion can't be done while the walker is active, instead the
634da14cebeSEric Cheng * deleting thread simply marks the entry as logically deleted. The last walker
635da14cebeSEric Cheng * physically deletes and frees up the logically deleted entries when the walk
636da14cebeSEric Cheng * is complete.
637da14cebeSEric Cheng */
638da14cebeSEric Cheng void
mac_callback_add(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head,mac_cb_t * mcb_elem)639da14cebeSEric Cheng mac_callback_add(mac_cb_info_t *mcbi, mac_cb_t **mcb_head,
640da14cebeSEric Cheng mac_cb_t *mcb_elem)
641da14cebeSEric Cheng {
642da14cebeSEric Cheng mac_cb_t *p;
643da14cebeSEric Cheng mac_cb_t **pp;
644da14cebeSEric Cheng
645da14cebeSEric Cheng /* Verify it is not already in the list */
646da14cebeSEric Cheng for (pp = mcb_head; (p = *pp) != NULL; pp = &p->mcb_nextp) {
647da14cebeSEric Cheng if (p == mcb_elem)
648da14cebeSEric Cheng break;
649da14cebeSEric Cheng }
650da14cebeSEric Cheng VERIFY(p == NULL);
651da14cebeSEric Cheng
652da14cebeSEric Cheng /*
653da14cebeSEric Cheng * Add it to the head of the callback list. The membar ensures that
654da14cebeSEric Cheng * the following list pointer manipulations reach global visibility
655da14cebeSEric Cheng * in exactly the program order below.
656da14cebeSEric Cheng */
657da14cebeSEric Cheng ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
658da14cebeSEric Cheng
659da14cebeSEric Cheng mcb_elem->mcb_nextp = *mcb_head;
660da14cebeSEric Cheng membar_producer();
661da14cebeSEric Cheng *mcb_head = mcb_elem;
662da14cebeSEric Cheng }
663da14cebeSEric Cheng
664da14cebeSEric Cheng /*
665da14cebeSEric Cheng * Mark the entry as logically deleted. If there aren't any walkers unlink
666da14cebeSEric Cheng * from the list. In either case return the corresponding status.
667da14cebeSEric Cheng */
668da14cebeSEric Cheng boolean_t
mac_callback_remove(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head,mac_cb_t * mcb_elem)669da14cebeSEric Cheng mac_callback_remove(mac_cb_info_t *mcbi, mac_cb_t **mcb_head,
670da14cebeSEric Cheng mac_cb_t *mcb_elem)
671da14cebeSEric Cheng {
672da14cebeSEric Cheng mac_cb_t *p;
673da14cebeSEric Cheng mac_cb_t **pp;
674da14cebeSEric Cheng
675da14cebeSEric Cheng ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
676da14cebeSEric Cheng /*
677da14cebeSEric Cheng * Search the callback list for the entry to be removed
678da14cebeSEric Cheng */
679da14cebeSEric Cheng for (pp = mcb_head; (p = *pp) != NULL; pp = &p->mcb_nextp) {
680da14cebeSEric Cheng if (p == mcb_elem)
681da14cebeSEric Cheng break;
682da14cebeSEric Cheng }
683da14cebeSEric Cheng VERIFY(p != NULL);
684da14cebeSEric Cheng
685da14cebeSEric Cheng /*
686da14cebeSEric Cheng * If there are walkers just mark it as deleted and the last walker
687da14cebeSEric Cheng * will remove from the list and free it.
688da14cebeSEric Cheng */
689da14cebeSEric Cheng if (mcbi->mcbi_walker_cnt != 0) {
690da14cebeSEric Cheng p->mcb_flags |= MCB_CONDEMNED;
691da14cebeSEric Cheng mcbi->mcbi_del_cnt++;
692da14cebeSEric Cheng return (B_FALSE);
693da14cebeSEric Cheng }
694da14cebeSEric Cheng
695da14cebeSEric Cheng ASSERT(mcbi->mcbi_del_cnt == 0);
696da14cebeSEric Cheng *pp = p->mcb_nextp;
697da14cebeSEric Cheng p->mcb_nextp = NULL;
698da14cebeSEric Cheng return (B_TRUE);
699da14cebeSEric Cheng }
700da14cebeSEric Cheng
701da14cebeSEric Cheng /*
702da14cebeSEric Cheng * Wait for all pending callback removals to be completed
703da14cebeSEric Cheng */
704da14cebeSEric Cheng void
mac_callback_remove_wait(mac_cb_info_t * mcbi)705da14cebeSEric Cheng mac_callback_remove_wait(mac_cb_info_t *mcbi)
706da14cebeSEric Cheng {
707da14cebeSEric Cheng ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
708da14cebeSEric Cheng while (mcbi->mcbi_del_cnt != 0) {
709da14cebeSEric Cheng DTRACE_PROBE1(need_wait, mac_cb_info_t *, mcbi);
710da14cebeSEric Cheng cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
711da14cebeSEric Cheng }
712da14cebeSEric Cheng }
713da14cebeSEric Cheng
714b237158dSPatrick Mooney void
mac_callback_barrier(mac_cb_info_t * mcbi)715b237158dSPatrick Mooney mac_callback_barrier(mac_cb_info_t *mcbi)
716b237158dSPatrick Mooney {
717b237158dSPatrick Mooney ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
718b237158dSPatrick Mooney ASSERT3U(mcbi->mcbi_barrier_cnt, <, UINT_MAX);
719b237158dSPatrick Mooney
720b237158dSPatrick Mooney if (mcbi->mcbi_walker_cnt == 0) {
721b237158dSPatrick Mooney return;
722b237158dSPatrick Mooney }
723b237158dSPatrick Mooney
724b237158dSPatrick Mooney mcbi->mcbi_barrier_cnt++;
725b237158dSPatrick Mooney do {
726b237158dSPatrick Mooney cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
727b237158dSPatrick Mooney } while (mcbi->mcbi_walker_cnt > 0);
728b237158dSPatrick Mooney mcbi->mcbi_barrier_cnt--;
729b237158dSPatrick Mooney cv_broadcast(&mcbi->mcbi_cv);
730b237158dSPatrick Mooney }
731b237158dSPatrick Mooney
732b237158dSPatrick Mooney void
mac_callback_walker_enter(mac_cb_info_t * mcbi)733b237158dSPatrick Mooney mac_callback_walker_enter(mac_cb_info_t *mcbi)
734b237158dSPatrick Mooney {
735b237158dSPatrick Mooney mutex_enter(mcbi->mcbi_lockp);
736b237158dSPatrick Mooney /*
737b237158dSPatrick Mooney * Incoming walkers should give precedence to timely clean-up of
738b237158dSPatrick Mooney * deleted callback entries and requested barriers.
739b237158dSPatrick Mooney */
740b237158dSPatrick Mooney while (mcbi->mcbi_del_cnt > 0 || mcbi->mcbi_barrier_cnt > 0) {
741b237158dSPatrick Mooney cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
742b237158dSPatrick Mooney }
743b237158dSPatrick Mooney mcbi->mcbi_walker_cnt++;
744b237158dSPatrick Mooney mutex_exit(mcbi->mcbi_lockp);
745b237158dSPatrick Mooney }
746b237158dSPatrick Mooney
747da14cebeSEric Cheng /*
748da14cebeSEric Cheng * The last mac callback walker does the cleanup. Walk the list and unlik
749da14cebeSEric Cheng * all the logically deleted entries and construct a temporary list of
750da14cebeSEric Cheng * removed entries. Return the list of removed entries to the caller.
751da14cebeSEric Cheng */
752b237158dSPatrick Mooney static mac_cb_t *
mac_callback_walker_cleanup(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head)753da14cebeSEric Cheng mac_callback_walker_cleanup(mac_cb_info_t *mcbi, mac_cb_t **mcb_head)
754da14cebeSEric Cheng {
755da14cebeSEric Cheng mac_cb_t *p;
756da14cebeSEric Cheng mac_cb_t **pp;
757da14cebeSEric Cheng mac_cb_t *rmlist = NULL; /* List of removed elements */
758da14cebeSEric Cheng int cnt = 0;
759da14cebeSEric Cheng
760da14cebeSEric Cheng ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
761da14cebeSEric Cheng ASSERT(mcbi->mcbi_del_cnt != 0 && mcbi->mcbi_walker_cnt == 0);
762da14cebeSEric Cheng
763da14cebeSEric Cheng pp = mcb_head;
764da14cebeSEric Cheng while (*pp != NULL) {
765da14cebeSEric Cheng if ((*pp)->mcb_flags & MCB_CONDEMNED) {
766da14cebeSEric Cheng p = *pp;
767da14cebeSEric Cheng *pp = p->mcb_nextp;
768da14cebeSEric Cheng p->mcb_nextp = rmlist;
769da14cebeSEric Cheng rmlist = p;
770da14cebeSEric Cheng cnt++;
771da14cebeSEric Cheng continue;
772da14cebeSEric Cheng }
773da14cebeSEric Cheng pp = &(*pp)->mcb_nextp;
774da14cebeSEric Cheng }
775da14cebeSEric Cheng
776da14cebeSEric Cheng ASSERT(mcbi->mcbi_del_cnt == cnt);
777da14cebeSEric Cheng mcbi->mcbi_del_cnt = 0;
778da14cebeSEric Cheng return (rmlist);
779da14cebeSEric Cheng }
780da14cebeSEric Cheng
781b237158dSPatrick Mooney void
mac_callback_walker_exit(mac_cb_info_t * mcbi,mac_cb_t ** headp,boolean_t is_promisc)782b237158dSPatrick Mooney mac_callback_walker_exit(mac_cb_info_t *mcbi, mac_cb_t **headp,
783b237158dSPatrick Mooney boolean_t is_promisc)
784b237158dSPatrick Mooney {
785b237158dSPatrick Mooney boolean_t do_wake = B_FALSE;
786b237158dSPatrick Mooney
787b237158dSPatrick Mooney mutex_enter(mcbi->mcbi_lockp);
788b237158dSPatrick Mooney
789b237158dSPatrick Mooney /* If walkers remain, nothing more can be done for now */
790b237158dSPatrick Mooney if (--mcbi->mcbi_walker_cnt != 0) {
791b237158dSPatrick Mooney mutex_exit(mcbi->mcbi_lockp);
792b237158dSPatrick Mooney return;
793b237158dSPatrick Mooney }
794b237158dSPatrick Mooney
795b237158dSPatrick Mooney if (mcbi->mcbi_del_cnt != 0) {
796b237158dSPatrick Mooney mac_cb_t *rmlist;
797b237158dSPatrick Mooney
798b237158dSPatrick Mooney rmlist = mac_callback_walker_cleanup(mcbi, headp);
799b237158dSPatrick Mooney
800b237158dSPatrick Mooney if (!is_promisc) {
801b237158dSPatrick Mooney /* The "normal" non-promisc callback clean-up */
802b237158dSPatrick Mooney mac_callback_free(rmlist);
803b237158dSPatrick Mooney } else {
804b237158dSPatrick Mooney mac_cb_t *mcb, *mcb_next;
805b237158dSPatrick Mooney
806b237158dSPatrick Mooney /*
807b237158dSPatrick Mooney * The promisc callbacks are in 2 lists, one off the
808b237158dSPatrick Mooney * 'mip' and another off the 'mcip' threaded by
809b237158dSPatrick Mooney * mpi_mi_link and mpi_mci_link respectively. There
810b237158dSPatrick Mooney * is, however, only a single shared total walker
811b237158dSPatrick Mooney * count, and an entry cannot be physically unlinked if
812b237158dSPatrick Mooney * a walker is active on either list. The last walker
813b237158dSPatrick Mooney * does this cleanup of logically deleted entries.
814b237158dSPatrick Mooney *
815b237158dSPatrick Mooney * With a list of callbacks deleted from above from
816b237158dSPatrick Mooney * mi_promisc_list (headp), remove the corresponding
817b237158dSPatrick Mooney * entry from mci_promisc_list (headp_pair) and free
818b237158dSPatrick Mooney * the structure.
819b237158dSPatrick Mooney */
820b237158dSPatrick Mooney for (mcb = rmlist; mcb != NULL; mcb = mcb_next) {
821b237158dSPatrick Mooney mac_promisc_impl_t *mpip;
822b237158dSPatrick Mooney mac_client_impl_t *mcip;
823b237158dSPatrick Mooney
824b237158dSPatrick Mooney mcb_next = mcb->mcb_nextp;
825b237158dSPatrick Mooney mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
826b237158dSPatrick Mooney mcip = mpip->mpi_mcip;
827b237158dSPatrick Mooney
828b237158dSPatrick Mooney ASSERT3P(&mcip->mci_mip->mi_promisc_cb_info,
829b237158dSPatrick Mooney ==, mcbi);
830b237158dSPatrick Mooney ASSERT3P(&mcip->mci_mip->mi_promisc_list,
831b237158dSPatrick Mooney ==, headp);
832b237158dSPatrick Mooney
833b237158dSPatrick Mooney VERIFY(mac_callback_remove(mcbi,
834b237158dSPatrick Mooney &mcip->mci_promisc_list,
835b237158dSPatrick Mooney &mpip->mpi_mci_link));
836b237158dSPatrick Mooney mcb->mcb_flags = 0;
837b237158dSPatrick Mooney mcb->mcb_nextp = NULL;
838b237158dSPatrick Mooney kmem_cache_free(mac_promisc_impl_cache, mpip);
839b237158dSPatrick Mooney }
840b237158dSPatrick Mooney }
841b237158dSPatrick Mooney
842b237158dSPatrick Mooney /*
843b237158dSPatrick Mooney * Wake any walker threads that could be waiting in
844b237158dSPatrick Mooney * mac_callback_walker_enter() until deleted items have been
845b237158dSPatrick Mooney * cleaned from the list.
846b237158dSPatrick Mooney */
847b237158dSPatrick Mooney do_wake = B_TRUE;
848b237158dSPatrick Mooney }
849b237158dSPatrick Mooney
850b237158dSPatrick Mooney if (mcbi->mcbi_barrier_cnt != 0) {
851b237158dSPatrick Mooney /*
852b237158dSPatrick Mooney * One or more threads are waiting for all walkers to exit the
853b237158dSPatrick Mooney * callback list. Notify them, now that the list is clear.
854b237158dSPatrick Mooney */
855b237158dSPatrick Mooney do_wake = B_TRUE;
856b237158dSPatrick Mooney }
857b237158dSPatrick Mooney
858b237158dSPatrick Mooney if (do_wake) {
859b237158dSPatrick Mooney cv_broadcast(&mcbi->mcbi_cv);
860b237158dSPatrick Mooney }
861b237158dSPatrick Mooney mutex_exit(mcbi->mcbi_lockp);
862b237158dSPatrick Mooney }
863b237158dSPatrick Mooney
864b237158dSPatrick Mooney static boolean_t
mac_callback_lookup(mac_cb_t ** mcb_headp,mac_cb_t * mcb_elem)865da14cebeSEric Cheng mac_callback_lookup(mac_cb_t **mcb_headp, mac_cb_t *mcb_elem)
866da14cebeSEric Cheng {
867da14cebeSEric Cheng mac_cb_t *mcb;
868da14cebeSEric Cheng
869da14cebeSEric Cheng /* Verify it is not already in the list */
870da14cebeSEric Cheng for (mcb = *mcb_headp; mcb != NULL; mcb = mcb->mcb_nextp) {
871da14cebeSEric Cheng if (mcb == mcb_elem)
872da14cebeSEric Cheng return (B_TRUE);
873da14cebeSEric Cheng }
874da14cebeSEric Cheng
875da14cebeSEric Cheng return (B_FALSE);
876da14cebeSEric Cheng }
877da14cebeSEric Cheng
878b237158dSPatrick Mooney static boolean_t
mac_callback_find(mac_cb_info_t * mcbi,mac_cb_t ** mcb_headp,mac_cb_t * mcb_elem)879da14cebeSEric Cheng mac_callback_find(mac_cb_info_t *mcbi, mac_cb_t **mcb_headp, mac_cb_t *mcb_elem)
880da14cebeSEric Cheng {
881da14cebeSEric Cheng boolean_t found;
882da14cebeSEric Cheng
883da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp);
884da14cebeSEric Cheng found = mac_callback_lookup(mcb_headp, mcb_elem);
885da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp);
886da14cebeSEric Cheng
887da14cebeSEric Cheng return (found);
888da14cebeSEric Cheng }
889da14cebeSEric Cheng
890da14cebeSEric Cheng /* Free the list of removed callbacks */
891da14cebeSEric Cheng void
mac_callback_free(mac_cb_t * rmlist)892da14cebeSEric Cheng mac_callback_free(mac_cb_t *rmlist)
893da14cebeSEric Cheng {
894da14cebeSEric Cheng mac_cb_t *mcb;
895da14cebeSEric Cheng mac_cb_t *mcb_next;
896da14cebeSEric Cheng
897da14cebeSEric Cheng for (mcb = rmlist; mcb != NULL; mcb = mcb_next) {
898da14cebeSEric Cheng mcb_next = mcb->mcb_nextp;
899da14cebeSEric Cheng kmem_free(mcb->mcb_objp, mcb->mcb_objsize);
900da14cebeSEric Cheng }
901da14cebeSEric Cheng }
902da14cebeSEric Cheng
903da14cebeSEric Cheng void
i_mac_notify(mac_impl_t * mip,mac_notify_type_t type)904da14cebeSEric Cheng i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
905da14cebeSEric Cheng {
906da14cebeSEric Cheng mac_cb_info_t *mcbi;
907da14cebeSEric Cheng
908da14cebeSEric Cheng /*
909da14cebeSEric Cheng * Signal the notify thread even after mi_ref has become zero and
910da14cebeSEric Cheng * mi_disabled is set. The synchronization with the notify thread
911da14cebeSEric Cheng * happens in mac_unregister and that implies the driver must make
912da14cebeSEric Cheng * sure it is single-threaded (with respect to mac calls) and that
913da14cebeSEric Cheng * all pending mac calls have returned before it calls mac_unregister
914da14cebeSEric Cheng */
915da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_READER);
916da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED)
917da14cebeSEric Cheng goto exit;
918da14cebeSEric Cheng
919da14cebeSEric Cheng /*
920da14cebeSEric Cheng * Guard against incorrect notifications. (Running a newer
921da14cebeSEric Cheng * mac client against an older implementation?)
922da14cebeSEric Cheng */
923da14cebeSEric Cheng if (type >= MAC_NNOTE)
924da14cebeSEric Cheng goto exit;
925da14cebeSEric Cheng
926da14cebeSEric Cheng mcbi = &mip->mi_notify_cb_info;
927da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp);
928da14cebeSEric Cheng mip->mi_notify_bits |= (1 << type);
929da14cebeSEric Cheng cv_broadcast(&mcbi->mcbi_cv);
930da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp);
931da14cebeSEric Cheng
932da14cebeSEric Cheng exit:
933da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
934da14cebeSEric Cheng }
935da14cebeSEric Cheng
936da14cebeSEric Cheng /*
937da14cebeSEric Cheng * Mac serialization primitives. Please see the block comment at the
938da14cebeSEric Cheng * top of the file.
939da14cebeSEric Cheng */
940da14cebeSEric Cheng void
i_mac_perim_enter(mac_impl_t * mip)941da14cebeSEric Cheng i_mac_perim_enter(mac_impl_t *mip)
942da14cebeSEric Cheng {
943da14cebeSEric Cheng mac_client_impl_t *mcip;
944da14cebeSEric Cheng
945da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) {
946da14cebeSEric Cheng /*
947da14cebeSEric Cheng * This is a VNIC. Return the lower mac since that is what
948da14cebeSEric Cheng * we want to serialize on.
949da14cebeSEric Cheng */
950da14cebeSEric Cheng mcip = mac_vnic_lower(mip);
951da14cebeSEric Cheng mip = mcip->mci_mip;
952da14cebeSEric Cheng }
953da14cebeSEric Cheng
954da14cebeSEric Cheng mutex_enter(&mip->mi_perim_lock);
955da14cebeSEric Cheng if (mip->mi_perim_owner == curthread) {
956da14cebeSEric Cheng mip->mi_perim_ocnt++;
957da14cebeSEric Cheng mutex_exit(&mip->mi_perim_lock);
958da14cebeSEric Cheng return;
959da14cebeSEric Cheng }
960da14cebeSEric Cheng
961da14cebeSEric Cheng while (mip->mi_perim_owner != NULL)
962da14cebeSEric Cheng cv_wait(&mip->mi_perim_cv, &mip->mi_perim_lock);
963da14cebeSEric Cheng
964da14cebeSEric Cheng mip->mi_perim_owner = curthread;
965da14cebeSEric Cheng ASSERT(mip->mi_perim_ocnt == 0);
966da14cebeSEric Cheng mip->mi_perim_ocnt++;
967da14cebeSEric Cheng #ifdef DEBUG
968da14cebeSEric Cheng mip->mi_perim_stack_depth = getpcstack(mip->mi_perim_stack,
969da14cebeSEric Cheng MAC_PERIM_STACK_DEPTH);
970da14cebeSEric Cheng #endif
971da14cebeSEric Cheng mutex_exit(&mip->mi_perim_lock);
972da14cebeSEric Cheng }
973da14cebeSEric Cheng
974da14cebeSEric Cheng int
i_mac_perim_enter_nowait(mac_impl_t * mip)975da14cebeSEric Cheng i_mac_perim_enter_nowait(mac_impl_t *mip)
976da14cebeSEric Cheng {
977da14cebeSEric Cheng /*
978da14cebeSEric Cheng * The vnic is a special case, since the serialization is done based
979da14cebeSEric Cheng * on the lower mac. If the lower mac is busy, it does not imply the
980da14cebeSEric Cheng * vnic can't be unregistered. But in the case of other drivers,
981da14cebeSEric Cheng * a busy perimeter or open mac handles implies that the mac is busy
982da14cebeSEric Cheng * and can't be unregistered.
983da14cebeSEric Cheng */
984da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) {
985da14cebeSEric Cheng i_mac_perim_enter(mip);
986da14cebeSEric Cheng return (0);
987da14cebeSEric Cheng }
988da14cebeSEric Cheng
989da14cebeSEric Cheng mutex_enter(&mip->mi_perim_lock);
990da14cebeSEric Cheng if (mip->mi_perim_owner != NULL) {
991da14cebeSEric Cheng mutex_exit(&mip->mi_perim_lock);
992da14cebeSEric Cheng return (EBUSY);
993da14cebeSEric Cheng }
994da14cebeSEric Cheng ASSERT(mip->mi_perim_ocnt == 0);
995da14cebeSEric Cheng mip->mi_perim_owner = curthread;
996da14cebeSEric Cheng mip->mi_perim_ocnt++;
997da14cebeSEric Cheng mutex_exit(&mip->mi_perim_lock);
998da14cebeSEric Cheng
999da14cebeSEric Cheng return (0);
1000da14cebeSEric Cheng }
1001da14cebeSEric Cheng
1002da14cebeSEric Cheng void
i_mac_perim_exit(mac_impl_t * mip)1003da14cebeSEric Cheng i_mac_perim_exit(mac_impl_t *mip)
1004da14cebeSEric Cheng {
1005da14cebeSEric Cheng mac_client_impl_t *mcip;
1006da14cebeSEric Cheng
1007da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) {
1008da14cebeSEric Cheng /*
1009da14cebeSEric Cheng * This is a VNIC. Return the lower mac since that is what
1010da14cebeSEric Cheng * we want to serialize on.
1011da14cebeSEric Cheng */
1012da14cebeSEric Cheng mcip = mac_vnic_lower(mip);
1013da14cebeSEric Cheng mip = mcip->mci_mip;
1014da14cebeSEric Cheng }
1015da14cebeSEric Cheng
1016da14cebeSEric Cheng ASSERT(mip->mi_perim_owner == curthread && mip->mi_perim_ocnt != 0);
1017da14cebeSEric Cheng
1018da14cebeSEric Cheng mutex_enter(&mip->mi_perim_lock);
1019da14cebeSEric Cheng if (--mip->mi_perim_ocnt == 0) {
1020da14cebeSEric Cheng mip->mi_perim_owner = NULL;
1021da14cebeSEric Cheng cv_signal(&mip->mi_perim_cv);
1022da14cebeSEric Cheng }
1023da14cebeSEric Cheng mutex_exit(&mip->mi_perim_lock);
1024da14cebeSEric Cheng }
1025da14cebeSEric Cheng
1026da14cebeSEric Cheng /*
1027da14cebeSEric Cheng * Returns whether the current thread holds the mac perimeter. Used in making
1028da14cebeSEric Cheng * assertions.
1029da14cebeSEric Cheng */
1030da14cebeSEric Cheng boolean_t
mac_perim_held(mac_handle_t mh)1031da14cebeSEric Cheng mac_perim_held(mac_handle_t mh)
1032da14cebeSEric Cheng {
1033da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
1034da14cebeSEric Cheng mac_client_impl_t *mcip;
1035da14cebeSEric Cheng
1036da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) {
1037da14cebeSEric Cheng /*
1038da14cebeSEric Cheng * This is a VNIC. Return the lower mac since that is what
1039da14cebeSEric Cheng * we want to serialize on.
1040da14cebeSEric Cheng */
1041da14cebeSEric Cheng mcip = mac_vnic_lower(mip);
1042da14cebeSEric Cheng mip = mcip->mci_mip;
1043da14cebeSEric Cheng }
1044da14cebeSEric Cheng return (mip->mi_perim_owner == curthread);
1045da14cebeSEric Cheng }
1046da14cebeSEric Cheng
1047da14cebeSEric Cheng /*
1048da14cebeSEric Cheng * mac client interfaces to enter the mac perimeter of a mac end point, given
1049da14cebeSEric Cheng * its mac handle, or macname or linkid.
1050da14cebeSEric Cheng */
1051da14cebeSEric Cheng void
mac_perim_enter_by_mh(mac_handle_t mh,mac_perim_handle_t * mphp)1052da14cebeSEric Cheng mac_perim_enter_by_mh(mac_handle_t mh, mac_perim_handle_t *mphp)
1053da14cebeSEric Cheng {
1054da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
1055da14cebeSEric Cheng
1056da14cebeSEric Cheng i_mac_perim_enter(mip);
1057da14cebeSEric Cheng /*
1058da14cebeSEric Cheng * The mac_perim_handle_t returned encodes the 'mip' and whether a
1059da14cebeSEric Cheng * mac_open has been done internally while entering the perimeter.
1060da14cebeSEric Cheng * This information is used in mac_perim_exit
1061da14cebeSEric Cheng */
1062da14cebeSEric Cheng MAC_ENCODE_MPH(*mphp, mip, 0);
1063da14cebeSEric Cheng }
1064da14cebeSEric Cheng
1065da14cebeSEric Cheng int
mac_perim_enter_by_macname(const char * name,mac_perim_handle_t * mphp)1066da14cebeSEric Cheng mac_perim_enter_by_macname(const char *name, mac_perim_handle_t *mphp)
1067da14cebeSEric Cheng {
1068da14cebeSEric Cheng int err;
1069da14cebeSEric Cheng mac_handle_t mh;
1070da14cebeSEric Cheng
1071da14cebeSEric Cheng if ((err = mac_open(name, &mh)) != 0)
1072da14cebeSEric Cheng return (err);
1073da14cebeSEric Cheng
1074da14cebeSEric Cheng mac_perim_enter_by_mh(mh, mphp);
1075da14cebeSEric Cheng MAC_ENCODE_MPH(*mphp, mh, 1);
1076da14cebeSEric Cheng return (0);
1077da14cebeSEric Cheng }
1078da14cebeSEric Cheng
1079da14cebeSEric Cheng int
mac_perim_enter_by_linkid(datalink_id_t linkid,mac_perim_handle_t * mphp)1080da14cebeSEric Cheng mac_perim_enter_by_linkid(datalink_id_t linkid, mac_perim_handle_t *mphp)
1081da14cebeSEric Cheng {
1082da14cebeSEric Cheng int err;
1083da14cebeSEric Cheng mac_handle_t mh;
1084da14cebeSEric Cheng
1085da14cebeSEric Cheng if ((err = mac_open_by_linkid(linkid, &mh)) != 0)
1086da14cebeSEric Cheng return (err);
1087da14cebeSEric Cheng
1088da14cebeSEric Cheng mac_perim_enter_by_mh(mh, mphp);
1089da14cebeSEric Cheng MAC_ENCODE_MPH(*mphp, mh, 1);
1090da14cebeSEric Cheng return (0);
1091da14cebeSEric Cheng }
1092da14cebeSEric Cheng
1093da14cebeSEric Cheng void
mac_perim_exit(mac_perim_handle_t mph)1094da14cebeSEric Cheng mac_perim_exit(mac_perim_handle_t mph)
1095da14cebeSEric Cheng {
1096da14cebeSEric Cheng mac_impl_t *mip;
1097da14cebeSEric Cheng boolean_t need_close;
1098da14cebeSEric Cheng
1099da14cebeSEric Cheng MAC_DECODE_MPH(mph, mip, need_close);
1100da14cebeSEric Cheng i_mac_perim_exit(mip);
1101da14cebeSEric Cheng if (need_close)
1102da14cebeSEric Cheng mac_close((mac_handle_t)mip);
1103da14cebeSEric Cheng }
1104da14cebeSEric Cheng
1105da14cebeSEric Cheng int
mac_hold(const char * macname,mac_impl_t ** pmip)1106d62bc4baSyz147064 mac_hold(const char *macname, mac_impl_t **pmip)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate mac_impl_t *mip;
11097c478bd9Sstevel@tonic-gate int err;
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate /*
11127c478bd9Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our
11137c478bd9Sstevel@tonic-gate * buffer.
11147c478bd9Sstevel@tonic-gate */
1115ba2e4443Sseb if (strlen(macname) >= MAXNAMELEN)
11167c478bd9Sstevel@tonic-gate return (EINVAL);
11177c478bd9Sstevel@tonic-gate
11187c478bd9Sstevel@tonic-gate /*
11197c478bd9Sstevel@tonic-gate * Look up its entry in the global hash table.
11207c478bd9Sstevel@tonic-gate */
1121210db224Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER);
1122ba2e4443Sseb err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
1123210db224Sericheng (mod_hash_val_t *)&mip);
1124d62bc4baSyz147064
1125210db224Sericheng if (err != 0) {
1126d62bc4baSyz147064 rw_exit(&i_mac_impl_lock);
1127d62bc4baSyz147064 return (ENOENT);
1128210db224Sericheng }
11297c478bd9Sstevel@tonic-gate
1130da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED) {
1131210db224Sericheng rw_exit(&i_mac_impl_lock);
1132d62bc4baSyz147064 return (ENOENT);
1133d62bc4baSyz147064 }
1134d62bc4baSyz147064
1135da14cebeSEric Cheng if (mip->mi_state_flags & MIS_EXCLUSIVE_HELD) {
1136d62bc4baSyz147064 rw_exit(&i_mac_impl_lock);
1137d62bc4baSyz147064 return (EBUSY);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate mip->mi_ref++;
1141210db224Sericheng rw_exit(&i_mac_impl_lock);
11427c478bd9Sstevel@tonic-gate
1143d62bc4baSyz147064 *pmip = mip;
1144d62bc4baSyz147064 return (0);
1145d62bc4baSyz147064 }
1146d62bc4baSyz147064
1147da14cebeSEric Cheng void
mac_rele(mac_impl_t * mip)1148d62bc4baSyz147064 mac_rele(mac_impl_t *mip)
1149d62bc4baSyz147064 {
1150d62bc4baSyz147064 rw_enter(&i_mac_impl_lock, RW_WRITER);
1151d62bc4baSyz147064 ASSERT(mip->mi_ref != 0);
1152da14cebeSEric Cheng if (--mip->mi_ref == 0) {
1153da14cebeSEric Cheng ASSERT(mip->mi_nactiveclients == 0 &&
1154da14cebeSEric Cheng !(mip->mi_state_flags & MIS_EXCLUSIVE));
1155da14cebeSEric Cheng }
1156d62bc4baSyz147064 rw_exit(&i_mac_impl_lock);
1157d62bc4baSyz147064 }
1158d62bc4baSyz147064
1159da14cebeSEric Cheng /*
11603bdd2dd4SMichael Lim * Private GLDv3 function to start a MAC instance.
1161da14cebeSEric Cheng */
1162d62bc4baSyz147064 int
mac_start(mac_handle_t mh)11633bdd2dd4SMichael Lim mac_start(mac_handle_t mh)
1164d62bc4baSyz147064 {
11653bdd2dd4SMichael Lim mac_impl_t *mip = (mac_impl_t *)mh;
1166da14cebeSEric Cheng int err = 0;
11670dc2366fSVenugopal Iyer mac_group_t *defgrp;
1168d62bc4baSyz147064
1169da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1170ba2e4443Sseb ASSERT(mip->mi_start != NULL);
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate /*
11737c478bd9Sstevel@tonic-gate * Check whether the device is already started.
11747c478bd9Sstevel@tonic-gate */
1175da14cebeSEric Cheng if (mip->mi_active++ == 0) {
1176da14cebeSEric Cheng mac_ring_t *ring = NULL;
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate /*
11797c478bd9Sstevel@tonic-gate * Start the device.
11807c478bd9Sstevel@tonic-gate */
1181da14cebeSEric Cheng err = mip->mi_start(mip->mi_driver);
1182da14cebeSEric Cheng if (err != 0) {
1183da14cebeSEric Cheng mip->mi_active--;
11847c478bd9Sstevel@tonic-gate return (err);
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate
1187da14cebeSEric Cheng /*
1188da14cebeSEric Cheng * Start the default tx ring.
1189da14cebeSEric Cheng */
1190da14cebeSEric Cheng if (mip->mi_default_tx_ring != NULL) {
1191da14cebeSEric Cheng
1192da14cebeSEric Cheng ring = (mac_ring_t *)mip->mi_default_tx_ring;
11930dc2366fSVenugopal Iyer if (ring->mr_state != MR_INUSE) {
1194da14cebeSEric Cheng err = mac_start_ring(ring);
1195da14cebeSEric Cheng if (err != 0) {
1196da14cebeSEric Cheng mip->mi_active--;
1197da14cebeSEric Cheng return (err);
1198da14cebeSEric Cheng }
11990dc2366fSVenugopal Iyer }
1200da14cebeSEric Cheng }
1201da14cebeSEric Cheng
12020dc2366fSVenugopal Iyer if ((defgrp = MAC_DEFAULT_RX_GROUP(mip)) != NULL) {
1203da14cebeSEric Cheng /*
120484de666eSRyan Zezeski * Start the default group which is responsible
120584de666eSRyan Zezeski * for receiving broadcast and multicast
120684de666eSRyan Zezeski * traffic for both primary and non-primary
120784de666eSRyan Zezeski * MAC clients.
1208da14cebeSEric Cheng */
12090dc2366fSVenugopal Iyer ASSERT(defgrp->mrg_state == MAC_GROUP_STATE_REGISTERED);
12100dc2366fSVenugopal Iyer err = mac_start_group_and_rings(defgrp);
1211da14cebeSEric Cheng if (err != 0) {
1212da14cebeSEric Cheng mip->mi_active--;
12130dc2366fSVenugopal Iyer if ((ring != NULL) &&
12140dc2366fSVenugopal Iyer (ring->mr_state == MR_INUSE))
1215da14cebeSEric Cheng mac_stop_ring(ring);
1216da14cebeSEric Cheng return (err);
1217da14cebeSEric Cheng }
12180dc2366fSVenugopal Iyer mac_set_group_state(defgrp, MAC_GROUP_STATE_SHARED);
1219da14cebeSEric Cheng }
1220da14cebeSEric Cheng }
1221da14cebeSEric Cheng
1222da14cebeSEric Cheng return (err);
1223da14cebeSEric Cheng }
1224da14cebeSEric Cheng
1225da14cebeSEric Cheng /*
12263bdd2dd4SMichael Lim * Private GLDv3 function to stop a MAC instance.
1227da14cebeSEric Cheng */
12287c478bd9Sstevel@tonic-gate void
mac_stop(mac_handle_t mh)12293bdd2dd4SMichael Lim mac_stop(mac_handle_t mh)
12307c478bd9Sstevel@tonic-gate {
12313bdd2dd4SMichael Lim mac_impl_t *mip = (mac_impl_t *)mh;
12320dc2366fSVenugopal Iyer mac_group_t *grp;
12333bdd2dd4SMichael Lim
1234ba2e4443Sseb ASSERT(mip->mi_stop != NULL);
1235da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate * Check whether the device is still needed.
12397c478bd9Sstevel@tonic-gate */
12407c478bd9Sstevel@tonic-gate ASSERT(mip->mi_active != 0);
1241da14cebeSEric Cheng if (--mip->mi_active == 0) {
12420dc2366fSVenugopal Iyer if ((grp = MAC_DEFAULT_RX_GROUP(mip)) != NULL) {
12437c478bd9Sstevel@tonic-gate /*
1244da14cebeSEric Cheng * There should be no more active clients since the
1245da14cebeSEric Cheng * MAC is being stopped. Stop the default RX group
1246da14cebeSEric Cheng * and transition it back to registered state.
12470dc2366fSVenugopal Iyer *
1248da14cebeSEric Cheng * When clients are torn down, the groups
1249da14cebeSEric Cheng * are release via mac_release_rx_group which
1250da14cebeSEric Cheng * knows the the default group is always in
1251da14cebeSEric Cheng * started mode since broadcast uses it. So
1252da14cebeSEric Cheng * we can assert that their are no clients
1253da14cebeSEric Cheng * (since mac_bcast_add doesn't register itself
1254da14cebeSEric Cheng * as a client) and group is in SHARED state.
1255da14cebeSEric Cheng */
1256da14cebeSEric Cheng ASSERT(grp->mrg_state == MAC_GROUP_STATE_SHARED);
12570dc2366fSVenugopal Iyer ASSERT(MAC_GROUP_NO_CLIENT(grp) &&
1258da14cebeSEric Cheng mip->mi_nactiveclients == 0);
1259da14cebeSEric Cheng mac_stop_group_and_rings(grp);
12600dc2366fSVenugopal Iyer mac_set_group_state(grp, MAC_GROUP_STATE_REGISTERED);
1261da14cebeSEric Cheng }
1262da14cebeSEric Cheng
1263da14cebeSEric Cheng if (mip->mi_default_tx_ring != NULL) {
1264da14cebeSEric Cheng mac_ring_t *ring;
1265da14cebeSEric Cheng
1266da14cebeSEric Cheng ring = (mac_ring_t *)mip->mi_default_tx_ring;
12670dc2366fSVenugopal Iyer if (ring->mr_state == MR_INUSE) {
1268da14cebeSEric Cheng mac_stop_ring(ring);
12690dc2366fSVenugopal Iyer ring->mr_flag = 0;
12700dc2366fSVenugopal Iyer }
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate * Stop the device.
12757c478bd9Sstevel@tonic-gate */
1276ba2e4443Sseb mip->mi_stop(mip->mi_driver);
1277ed8845d8Skrgopi }
1278ed8845d8Skrgopi }
1279ed8845d8Skrgopi
12807c478bd9Sstevel@tonic-gate int
i_mac_promisc_set(mac_impl_t * mip,boolean_t on)1281d91a22bfSGirish Moodalbail i_mac_promisc_set(mac_impl_t *mip, boolean_t on)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate int err = 0;
12847c478bd9Sstevel@tonic-gate
1285da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1286ba2e4443Sseb ASSERT(mip->mi_setpromisc != NULL);
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate if (on) {
12897c478bd9Sstevel@tonic-gate /*
12907c478bd9Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled.
12917c478bd9Sstevel@tonic-gate */
12927c478bd9Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) {
1293ba2e4443Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
1294ba2e4443Sseb if (err != 0) {
12957c478bd9Sstevel@tonic-gate mip->mi_devpromisc--;
1296da14cebeSEric Cheng return (err);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate } else {
1301da14cebeSEric Cheng if (mip->mi_devpromisc == 0)
1302da14cebeSEric Cheng return (EPROTO);
1303da14cebeSEric Cheng
13047c478bd9Sstevel@tonic-gate /*
13057c478bd9Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last
13067c478bd9Sstevel@tonic-gate * enabling.
13077c478bd9Sstevel@tonic-gate */
13087c478bd9Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) {
1309ba2e4443Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
1310ba2e4443Sseb if (err != 0) {
13117c478bd9Sstevel@tonic-gate mip->mi_devpromisc++;
1312da14cebeSEric Cheng return (err);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
13157c478bd9Sstevel@tonic-gate }
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate
1318da14cebeSEric Cheng return (0);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate
1321da14cebeSEric Cheng /*
1322da14cebeSEric Cheng * The promiscuity state can change any time. If the caller needs to take
1323da14cebeSEric Cheng * actions that are atomic with the promiscuity state, then the caller needs
1324da14cebeSEric Cheng * to bracket the entire sequence with mac_perim_enter/exit
1325da14cebeSEric Cheng */
13267c478bd9Sstevel@tonic-gate boolean_t
mac_promisc_get(mac_handle_t mh)1327d91a22bfSGirish Moodalbail mac_promisc_get(mac_handle_t mh)
13287c478bd9Sstevel@tonic-gate {
13297c478bd9Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh;
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate * Return the current promiscuity.
13337c478bd9Sstevel@tonic-gate */
13347c478bd9Sstevel@tonic-gate return (mip->mi_devpromisc != 0);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
1337da14cebeSEric Cheng /*
1338da14cebeSEric Cheng * Invoked at MAC instance attach time to initialize the list
1339da14cebeSEric Cheng * of factory MAC addresses supported by a MAC instance. This function
1340da14cebeSEric Cheng * builds a local cache in the mac_impl_t for the MAC addresses
1341da14cebeSEric Cheng * supported by the underlying hardware. The MAC clients themselves
1342da14cebeSEric Cheng * use the mac_addr_factory*() functions to query and reserve
1343da14cebeSEric Cheng * factory MAC addresses.
1344da14cebeSEric Cheng */
13457c478bd9Sstevel@tonic-gate void
mac_addr_factory_init(mac_impl_t * mip)1346da14cebeSEric Cheng mac_addr_factory_init(mac_impl_t *mip)
1347e7801d59Ssowmini {
1348da14cebeSEric Cheng mac_capab_multifactaddr_t capab;
1349da14cebeSEric Cheng uint8_t *addr;
1350da14cebeSEric Cheng int i;
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate /*
1353da14cebeSEric Cheng * First round to see how many factory MAC addresses are available.
13547c478bd9Sstevel@tonic-gate */
1355da14cebeSEric Cheng bzero(&capab, sizeof (capab));
1356da14cebeSEric Cheng if (!i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_MULTIFACTADDR,
1357da14cebeSEric Cheng &capab) || (capab.mcm_naddr == 0)) {
1358e7801d59Ssowmini /*
1359da14cebeSEric Cheng * The MAC instance doesn't support multiple factory
1360da14cebeSEric Cheng * MAC addresses, we're done here.
1361e7801d59Ssowmini */
13624045d941Ssowmini return;
1363e7801d59Ssowmini }
13644045d941Ssowmini
13657c478bd9Sstevel@tonic-gate /*
1366da14cebeSEric Cheng * Allocate the space and get all the factory addresses.
13677c478bd9Sstevel@tonic-gate */
1368da14cebeSEric Cheng addr = kmem_alloc(capab.mcm_naddr * MAXMACADDRLEN, KM_SLEEP);
1369da14cebeSEric Cheng capab.mcm_getaddr(mip->mi_driver, capab.mcm_naddr, addr);
1370da14cebeSEric Cheng
1371da14cebeSEric Cheng mip->mi_factory_addr_num = capab.mcm_naddr;
1372da14cebeSEric Cheng mip->mi_factory_addr = kmem_zalloc(mip->mi_factory_addr_num *
1373da14cebeSEric Cheng sizeof (mac_factory_addr_t), KM_SLEEP);
1374da14cebeSEric Cheng
1375da14cebeSEric Cheng for (i = 0; i < capab.mcm_naddr; i++) {
1376da14cebeSEric Cheng bcopy(addr + i * MAXMACADDRLEN,
1377da14cebeSEric Cheng mip->mi_factory_addr[i].mfa_addr,
1378da14cebeSEric Cheng mip->mi_type->mt_addr_length);
1379da14cebeSEric Cheng mip->mi_factory_addr[i].mfa_in_use = B_FALSE;
1380da14cebeSEric Cheng }
1381da14cebeSEric Cheng
1382da14cebeSEric Cheng kmem_free(addr, capab.mcm_naddr * MAXMACADDRLEN);
1383da14cebeSEric Cheng }
1384da14cebeSEric Cheng
1385da14cebeSEric Cheng void
mac_addr_factory_fini(mac_impl_t * mip)1386da14cebeSEric Cheng mac_addr_factory_fini(mac_impl_t *mip)
1387da14cebeSEric Cheng {
1388da14cebeSEric Cheng if (mip->mi_factory_addr == NULL) {
1389da14cebeSEric Cheng ASSERT(mip->mi_factory_addr_num == 0);
1390da14cebeSEric Cheng return;
1391da14cebeSEric Cheng }
1392da14cebeSEric Cheng
1393da14cebeSEric Cheng kmem_free(mip->mi_factory_addr, mip->mi_factory_addr_num *
1394da14cebeSEric Cheng sizeof (mac_factory_addr_t));
1395da14cebeSEric Cheng
1396da14cebeSEric Cheng mip->mi_factory_addr = NULL;
1397da14cebeSEric Cheng mip->mi_factory_addr_num = 0;
1398da14cebeSEric Cheng }
1399da14cebeSEric Cheng
1400da14cebeSEric Cheng /*
1401da14cebeSEric Cheng * Reserve a factory MAC address. If *slot is set to -1, the function
1402da14cebeSEric Cheng * attempts to reserve any of the available factory MAC addresses and
1403da14cebeSEric Cheng * returns the reserved slot id. If no slots are available, the function
1404da14cebeSEric Cheng * returns ENOSPC. If *slot is not set to -1, the function reserves
1405da14cebeSEric Cheng * the specified slot if it is available, or returns EBUSY is the slot
1406da14cebeSEric Cheng * is already used. Returns ENOTSUP if the underlying MAC does not
1407da14cebeSEric Cheng * support multiple factory addresses. If the slot number is not -1 but
1408da14cebeSEric Cheng * is invalid, returns EINVAL.
1409da14cebeSEric Cheng */
1410da14cebeSEric Cheng int
mac_addr_factory_reserve(mac_client_handle_t mch,int * slot)1411da14cebeSEric Cheng mac_addr_factory_reserve(mac_client_handle_t mch, int *slot)
1412da14cebeSEric Cheng {
1413da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1414da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
1415da14cebeSEric Cheng int i, ret = 0;
1416da14cebeSEric Cheng
1417da14cebeSEric Cheng i_mac_perim_enter(mip);
1418da14cebeSEric Cheng /*
1419da14cebeSEric Cheng * Protect against concurrent readers that may need a self-consistent
1420da14cebeSEric Cheng * view of the factory addresses
1421da14cebeSEric Cheng */
1422da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER);
1423da14cebeSEric Cheng
1424da14cebeSEric Cheng if (mip->mi_factory_addr_num == 0) {
1425da14cebeSEric Cheng ret = ENOTSUP;
1426da14cebeSEric Cheng goto bail;
1427da14cebeSEric Cheng }
1428da14cebeSEric Cheng
1429da14cebeSEric Cheng if (*slot != -1) {
1430da14cebeSEric Cheng /* check the specified slot */
1431da14cebeSEric Cheng if (*slot < 1 || *slot > mip->mi_factory_addr_num) {
1432da14cebeSEric Cheng ret = EINVAL;
1433da14cebeSEric Cheng goto bail;
1434da14cebeSEric Cheng }
1435da14cebeSEric Cheng if (mip->mi_factory_addr[*slot-1].mfa_in_use) {
1436da14cebeSEric Cheng ret = EBUSY;
1437da14cebeSEric Cheng goto bail;
1438da14cebeSEric Cheng }
1439da14cebeSEric Cheng } else {
1440da14cebeSEric Cheng /* pick the next available slot */
1441da14cebeSEric Cheng for (i = 0; i < mip->mi_factory_addr_num; i++) {
1442da14cebeSEric Cheng if (!mip->mi_factory_addr[i].mfa_in_use)
1443da14cebeSEric Cheng break;
1444da14cebeSEric Cheng }
1445da14cebeSEric Cheng
1446da14cebeSEric Cheng if (i == mip->mi_factory_addr_num) {
1447da14cebeSEric Cheng ret = ENOSPC;
1448da14cebeSEric Cheng goto bail;
1449da14cebeSEric Cheng }
1450da14cebeSEric Cheng *slot = i+1;
1451da14cebeSEric Cheng }
1452da14cebeSEric Cheng
1453da14cebeSEric Cheng mip->mi_factory_addr[*slot-1].mfa_in_use = B_TRUE;
1454da14cebeSEric Cheng mip->mi_factory_addr[*slot-1].mfa_client = mcip;
1455da14cebeSEric Cheng
1456da14cebeSEric Cheng bail:
1457da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock);
1458da14cebeSEric Cheng i_mac_perim_exit(mip);
1459da14cebeSEric Cheng return (ret);
1460da14cebeSEric Cheng }
1461da14cebeSEric Cheng
1462da14cebeSEric Cheng /*
1463da14cebeSEric Cheng * Release the specified factory MAC address slot.
1464da14cebeSEric Cheng */
1465da14cebeSEric Cheng void
mac_addr_factory_release(mac_client_handle_t mch,uint_t slot)1466da14cebeSEric Cheng mac_addr_factory_release(mac_client_handle_t mch, uint_t slot)
1467da14cebeSEric Cheng {
1468da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1469da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
1470da14cebeSEric Cheng
1471da14cebeSEric Cheng i_mac_perim_enter(mip);
1472da14cebeSEric Cheng /*
1473da14cebeSEric Cheng * Protect against concurrent readers that may need a self-consistent
1474da14cebeSEric Cheng * view of the factory addresses
1475da14cebeSEric Cheng */
1476da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER);
1477da14cebeSEric Cheng
1478da14cebeSEric Cheng ASSERT(slot > 0 && slot <= mip->mi_factory_addr_num);
1479da14cebeSEric Cheng ASSERT(mip->mi_factory_addr[slot-1].mfa_in_use);
1480da14cebeSEric Cheng
1481da14cebeSEric Cheng mip->mi_factory_addr[slot-1].mfa_in_use = B_FALSE;
1482da14cebeSEric Cheng
1483da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock);
1484da14cebeSEric Cheng i_mac_perim_exit(mip);
1485da14cebeSEric Cheng }
1486da14cebeSEric Cheng
1487da14cebeSEric Cheng /*
1488da14cebeSEric Cheng * Stores in mac_addr the value of the specified MAC address. Returns
1489da14cebeSEric Cheng * 0 on success, or EINVAL if the slot number is not valid for the MAC.
1490da14cebeSEric Cheng * The caller must provide a string of at least MAXNAMELEN bytes.
1491da14cebeSEric Cheng */
1492da14cebeSEric Cheng void
mac_addr_factory_value(mac_handle_t mh,int slot,uchar_t * mac_addr,uint_t * addr_len,char * client_name,boolean_t * in_use_arg)1493da14cebeSEric Cheng mac_addr_factory_value(mac_handle_t mh, int slot, uchar_t *mac_addr,
1494da14cebeSEric Cheng uint_t *addr_len, char *client_name, boolean_t *in_use_arg)
1495da14cebeSEric Cheng {
1496da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
1497da14cebeSEric Cheng boolean_t in_use;
1498da14cebeSEric Cheng
1499da14cebeSEric Cheng ASSERT(slot > 0 && slot <= mip->mi_factory_addr_num);
1500da14cebeSEric Cheng
1501da14cebeSEric Cheng /*
1502da14cebeSEric Cheng * Readers need to hold mi_rw_lock. Writers need to hold mac perimeter
1503da14cebeSEric Cheng * and mi_rw_lock
1504da14cebeSEric Cheng */
1505da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER);
1506da14cebeSEric Cheng bcopy(mip->mi_factory_addr[slot-1].mfa_addr, mac_addr, MAXMACADDRLEN);
1507da14cebeSEric Cheng *addr_len = mip->mi_type->mt_addr_length;
1508da14cebeSEric Cheng in_use = mip->mi_factory_addr[slot-1].mfa_in_use;
1509da14cebeSEric Cheng if (in_use && client_name != NULL) {
1510da14cebeSEric Cheng bcopy(mip->mi_factory_addr[slot-1].mfa_client->mci_name,
1511da14cebeSEric Cheng client_name, MAXNAMELEN);
1512da14cebeSEric Cheng }
1513da14cebeSEric Cheng if (in_use_arg != NULL)
1514da14cebeSEric Cheng *in_use_arg = in_use;
1515da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock);
1516da14cebeSEric Cheng }
1517da14cebeSEric Cheng
1518da14cebeSEric Cheng /*
1519da14cebeSEric Cheng * Returns the number of factory MAC addresses (in addition to the
1520da14cebeSEric Cheng * primary MAC address), 0 if the underlying MAC doesn't support
1521da14cebeSEric Cheng * that feature.
1522da14cebeSEric Cheng */
1523da14cebeSEric Cheng uint_t
mac_addr_factory_num(mac_handle_t mh)1524da14cebeSEric Cheng mac_addr_factory_num(mac_handle_t mh)
1525da14cebeSEric Cheng {
1526da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
1527da14cebeSEric Cheng
1528da14cebeSEric Cheng return (mip->mi_factory_addr_num);
1529da14cebeSEric Cheng }
1530da14cebeSEric Cheng
1531da14cebeSEric Cheng
1532da14cebeSEric Cheng void
mac_rx_group_unmark(mac_group_t * grp,uint_t flag)1533da14cebeSEric Cheng mac_rx_group_unmark(mac_group_t *grp, uint_t flag)
1534da14cebeSEric Cheng {
1535da14cebeSEric Cheng mac_ring_t *ring;
1536da14cebeSEric Cheng
1537da14cebeSEric Cheng for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next)
1538da14cebeSEric Cheng ring->mr_flag &= ~flag;
1539da14cebeSEric Cheng }
1540da14cebeSEric Cheng
1541da14cebeSEric Cheng /*
1542da14cebeSEric Cheng * The following mac_hwrings_xxx() functions are private mac client functions
1543da14cebeSEric Cheng * used by the aggr driver to access and control the underlying HW Rx group
1544da14cebeSEric Cheng * and rings. In this case, the aggr driver has exclusive control of the
1545da14cebeSEric Cheng * underlying HW Rx group/rings, it calls the following functions to
154645948e49SRyan Zezeski * start/stop the HW Rx rings, disable/enable polling, add/remove MAC
1547da14cebeSEric Cheng * addresses, or set up the Rx callback.
1548da14cebeSEric Cheng */
1549da14cebeSEric Cheng /* ARGSUSED */
1550da14cebeSEric Cheng static void
mac_hwrings_rx_process(void * arg,mac_resource_handle_t srs,mblk_t * mp_chain,boolean_t loopback)1551da14cebeSEric Cheng mac_hwrings_rx_process(void *arg, mac_resource_handle_t srs,
1552da14cebeSEric Cheng mblk_t *mp_chain, boolean_t loopback)
1553da14cebeSEric Cheng {
1554da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs = (mac_soft_ring_set_t *)srs;
1555da14cebeSEric Cheng mac_srs_rx_t *srs_rx = &mac_srs->srs_rx;
1556da14cebeSEric Cheng mac_direct_rx_t proc;
1557da14cebeSEric Cheng void *arg1;
1558da14cebeSEric Cheng mac_resource_handle_t arg2;
1559da14cebeSEric Cheng
1560da14cebeSEric Cheng proc = srs_rx->sr_func;
1561da14cebeSEric Cheng arg1 = srs_rx->sr_arg1;
1562da14cebeSEric Cheng arg2 = mac_srs->srs_mrh;
1563da14cebeSEric Cheng
1564da14cebeSEric Cheng proc(arg1, arg2, mp_chain, NULL);
1565da14cebeSEric Cheng }
1566da14cebeSEric Cheng
1567da14cebeSEric Cheng /*
1568da14cebeSEric Cheng * This function is called to get the list of HW rings that are reserved by
1569da14cebeSEric Cheng * an exclusive mac client.
1570da14cebeSEric Cheng *
1571da14cebeSEric Cheng * Return value: the number of HW rings.
1572da14cebeSEric Cheng */
1573da14cebeSEric Cheng int
mac_hwrings_get(mac_client_handle_t mch,mac_group_handle_t * hwgh,mac_ring_handle_t * hwrh,mac_ring_type_t rtype)1574da14cebeSEric Cheng mac_hwrings_get(mac_client_handle_t mch, mac_group_handle_t *hwgh,
157563f531d1SSriharsha Basavapatna mac_ring_handle_t *hwrh, mac_ring_type_t rtype)
1576da14cebeSEric Cheng {
1577da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
157863f531d1SSriharsha Basavapatna flow_entry_t *flent = mcip->mci_flent;
157963f531d1SSriharsha Basavapatna mac_group_t *grp;
158063f531d1SSriharsha Basavapatna mac_ring_t *ring;
15810dc2366fSVenugopal Iyer int cnt = 0;
158263f531d1SSriharsha Basavapatna
15830dc2366fSVenugopal Iyer if (rtype == MAC_RING_TYPE_RX) {
158463f531d1SSriharsha Basavapatna grp = flent->fe_rx_ring_group;
15850dc2366fSVenugopal Iyer } else if (rtype == MAC_RING_TYPE_TX) {
15860dc2366fSVenugopal Iyer grp = flent->fe_tx_ring_group;
15870dc2366fSVenugopal Iyer } else {
15880dc2366fSVenugopal Iyer ASSERT(B_FALSE);
15890dc2366fSVenugopal Iyer return (-1);
15900dc2366fSVenugopal Iyer }
159145948e49SRyan Zezeski
1592da14cebeSEric Cheng /*
159345948e49SRyan Zezeski * The MAC client did not reserve an Rx group, return directly.
1594da14cebeSEric Cheng * This is probably because the underlying MAC does not support
159563f531d1SSriharsha Basavapatna * any groups.
1596da14cebeSEric Cheng */
15970dc2366fSVenugopal Iyer if (hwgh != NULL)
1598da14cebeSEric Cheng *hwgh = NULL;
1599da14cebeSEric Cheng if (grp == NULL)
1600da14cebeSEric Cheng return (0);
1601da14cebeSEric Cheng /*
160245948e49SRyan Zezeski * This group must be reserved by this MAC client.
1603da14cebeSEric Cheng */
1604da14cebeSEric Cheng ASSERT((grp->mrg_state == MAC_GROUP_STATE_RESERVED) &&
16050dc2366fSVenugopal Iyer (mcip == MAC_GROUP_ONLY_CLIENT(grp)));
16060dc2366fSVenugopal Iyer
16070dc2366fSVenugopal Iyer for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
1608da14cebeSEric Cheng ASSERT(cnt < MAX_RINGS_PER_GROUP);
160963f531d1SSriharsha Basavapatna hwrh[cnt] = (mac_ring_handle_t)ring;
1610da14cebeSEric Cheng }
16110dc2366fSVenugopal Iyer if (hwgh != NULL)
1612da14cebeSEric Cheng *hwgh = (mac_group_handle_t)grp;
161363f531d1SSriharsha Basavapatna
161463f531d1SSriharsha Basavapatna return (cnt);
161563f531d1SSriharsha Basavapatna }
1616da14cebeSEric Cheng
1617da14cebeSEric Cheng /*
161845948e49SRyan Zezeski * Get the HW ring handles of the given group index. If the MAC
161945948e49SRyan Zezeski * doesn't have a group at this index, or any groups at all, then 0 is
162045948e49SRyan Zezeski * returned and hwgh is set to NULL. This is a private client API. The
162145948e49SRyan Zezeski * MAC perimeter must be held when calling this function.
162245948e49SRyan Zezeski *
162345948e49SRyan Zezeski * mh: A handle to the MAC that owns the group.
162445948e49SRyan Zezeski *
162545948e49SRyan Zezeski * idx: The index of the HW group to be read.
162645948e49SRyan Zezeski *
162745948e49SRyan Zezeski * hwgh: If non-NULL, contains a handle to the HW group on return.
162845948e49SRyan Zezeski *
162945948e49SRyan Zezeski * hwrh: An array of ring handles pointing to the HW rings in the
163045948e49SRyan Zezeski * group. The array must be large enough to hold a handle to each ring
163145948e49SRyan Zezeski * in the group. To be safe, this array should be of size MAX_RINGS_PER_GROUP.
163245948e49SRyan Zezeski *
163345948e49SRyan Zezeski * rtype: Used to determine if we are fetching Rx or Tx rings.
163445948e49SRyan Zezeski *
163545948e49SRyan Zezeski * Returns the number of rings in the group.
163645948e49SRyan Zezeski */
163745948e49SRyan Zezeski uint_t
mac_hwrings_idx_get(mac_handle_t mh,uint_t idx,mac_group_handle_t * hwgh,mac_ring_handle_t * hwrh,mac_ring_type_t rtype)163845948e49SRyan Zezeski mac_hwrings_idx_get(mac_handle_t mh, uint_t idx, mac_group_handle_t *hwgh,
163945948e49SRyan Zezeski mac_ring_handle_t *hwrh, mac_ring_type_t rtype)
164045948e49SRyan Zezeski {
164145948e49SRyan Zezeski mac_impl_t *mip = (mac_impl_t *)mh;
164245948e49SRyan Zezeski mac_group_t *grp;
164345948e49SRyan Zezeski mac_ring_t *ring;
164445948e49SRyan Zezeski uint_t cnt = 0;
164545948e49SRyan Zezeski
164645948e49SRyan Zezeski /*
164745948e49SRyan Zezeski * The MAC perimeter must be held when accessing the
164845948e49SRyan Zezeski * mi_{rx,tx}_groups fields.
164945948e49SRyan Zezeski */
165045948e49SRyan Zezeski ASSERT(MAC_PERIM_HELD(mh));
165145948e49SRyan Zezeski ASSERT(rtype == MAC_RING_TYPE_RX || rtype == MAC_RING_TYPE_TX);
165245948e49SRyan Zezeski
165345948e49SRyan Zezeski if (rtype == MAC_RING_TYPE_RX) {
165445948e49SRyan Zezeski grp = mip->mi_rx_groups;
165545948e49SRyan Zezeski } else {
165645948e49SRyan Zezeski ASSERT(rtype == MAC_RING_TYPE_TX);
165745948e49SRyan Zezeski grp = mip->mi_tx_groups;
165845948e49SRyan Zezeski }
165945948e49SRyan Zezeski
166045948e49SRyan Zezeski while (grp != NULL && grp->mrg_index != idx)
166145948e49SRyan Zezeski grp = grp->mrg_next;
166245948e49SRyan Zezeski
166345948e49SRyan Zezeski /*
166445948e49SRyan Zezeski * If the MAC doesn't have a group at this index or doesn't
166545948e49SRyan Zezeski * impelement RINGS capab, then set hwgh to NULL and return 0.
166645948e49SRyan Zezeski */
166745948e49SRyan Zezeski if (hwgh != NULL)
166845948e49SRyan Zezeski *hwgh = NULL;
166945948e49SRyan Zezeski
167045948e49SRyan Zezeski if (grp == NULL)
167145948e49SRyan Zezeski return (0);
167245948e49SRyan Zezeski
167345948e49SRyan Zezeski ASSERT3U(idx, ==, grp->mrg_index);
167445948e49SRyan Zezeski
167545948e49SRyan Zezeski for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
167645948e49SRyan Zezeski ASSERT3U(cnt, <, MAX_RINGS_PER_GROUP);
167745948e49SRyan Zezeski hwrh[cnt] = (mac_ring_handle_t)ring;
167845948e49SRyan Zezeski }
167945948e49SRyan Zezeski
168045948e49SRyan Zezeski /* A group should always have at least one ring. */
168145948e49SRyan Zezeski ASSERT3U(cnt, >, 0);
168245948e49SRyan Zezeski
168345948e49SRyan Zezeski if (hwgh != NULL)
168445948e49SRyan Zezeski *hwgh = (mac_group_handle_t)grp;
168545948e49SRyan Zezeski
168645948e49SRyan Zezeski return (cnt);
168745948e49SRyan Zezeski }
168845948e49SRyan Zezeski
168945948e49SRyan Zezeski /*
16900dc2366fSVenugopal Iyer * This function is called to get info about Tx/Rx rings.
16910dc2366fSVenugopal Iyer *
16920dc2366fSVenugopal Iyer * Return value: returns uint_t which will have various bits set
16930dc2366fSVenugopal Iyer * that indicates different properties of the ring.
16940dc2366fSVenugopal Iyer */
16950dc2366fSVenugopal Iyer uint_t
mac_hwring_getinfo(mac_ring_handle_t rh)16960dc2366fSVenugopal Iyer mac_hwring_getinfo(mac_ring_handle_t rh)
16970dc2366fSVenugopal Iyer {
16980dc2366fSVenugopal Iyer mac_ring_t *ring = (mac_ring_t *)rh;
16990dc2366fSVenugopal Iyer mac_ring_info_t *info = &ring->mr_info;
17000dc2366fSVenugopal Iyer
17010dc2366fSVenugopal Iyer return (info->mri_flags);
17020dc2366fSVenugopal Iyer }
17030dc2366fSVenugopal Iyer
17040dc2366fSVenugopal Iyer /*
170545948e49SRyan Zezeski * Set the passthru callback on the hardware ring.
170645948e49SRyan Zezeski */
170745948e49SRyan Zezeski void
mac_hwring_set_passthru(mac_ring_handle_t hwrh,mac_rx_t fn,void * arg1,mac_resource_handle_t arg2)170845948e49SRyan Zezeski mac_hwring_set_passthru(mac_ring_handle_t hwrh, mac_rx_t fn, void *arg1,
170945948e49SRyan Zezeski mac_resource_handle_t arg2)
171045948e49SRyan Zezeski {
171145948e49SRyan Zezeski mac_ring_t *hwring = (mac_ring_t *)hwrh;
171245948e49SRyan Zezeski
171345948e49SRyan Zezeski ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
171445948e49SRyan Zezeski
171545948e49SRyan Zezeski hwring->mr_classify_type = MAC_PASSTHRU_CLASSIFIER;
171645948e49SRyan Zezeski
171745948e49SRyan Zezeski hwring->mr_pt_fn = fn;
171845948e49SRyan Zezeski hwring->mr_pt_arg1 = arg1;
171945948e49SRyan Zezeski hwring->mr_pt_arg2 = arg2;
172045948e49SRyan Zezeski }
172145948e49SRyan Zezeski
172245948e49SRyan Zezeski /*
172345948e49SRyan Zezeski * Clear the passthru callback on the hardware ring.
172445948e49SRyan Zezeski */
172545948e49SRyan Zezeski void
mac_hwring_clear_passthru(mac_ring_handle_t hwrh)172645948e49SRyan Zezeski mac_hwring_clear_passthru(mac_ring_handle_t hwrh)
172745948e49SRyan Zezeski {
172845948e49SRyan Zezeski mac_ring_t *hwring = (mac_ring_t *)hwrh;
172945948e49SRyan Zezeski
173045948e49SRyan Zezeski ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
173145948e49SRyan Zezeski
173245948e49SRyan Zezeski hwring->mr_classify_type = MAC_NO_CLASSIFIER;
173345948e49SRyan Zezeski
173445948e49SRyan Zezeski hwring->mr_pt_fn = NULL;
173545948e49SRyan Zezeski hwring->mr_pt_arg1 = NULL;
173645948e49SRyan Zezeski hwring->mr_pt_arg2 = NULL;
173745948e49SRyan Zezeski }
173845948e49SRyan Zezeski
173945948e49SRyan Zezeski void
mac_client_set_flow_cb(mac_client_handle_t mch,mac_rx_t func,void * arg1)174045948e49SRyan Zezeski mac_client_set_flow_cb(mac_client_handle_t mch, mac_rx_t func, void *arg1)
174145948e49SRyan Zezeski {
174245948e49SRyan Zezeski mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
174345948e49SRyan Zezeski flow_entry_t *flent = mcip->mci_flent;
174445948e49SRyan Zezeski
174545948e49SRyan Zezeski mutex_enter(&flent->fe_lock);
174645948e49SRyan Zezeski flent->fe_cb_fn = (flow_fn_t)func;
174745948e49SRyan Zezeski flent->fe_cb_arg1 = arg1;
174845948e49SRyan Zezeski flent->fe_cb_arg2 = NULL;
174945948e49SRyan Zezeski flent->fe_flags &= ~FE_MC_NO_DATAPATH;
175045948e49SRyan Zezeski mutex_exit(&flent->fe_lock);
175145948e49SRyan Zezeski }
175245948e49SRyan Zezeski
175345948e49SRyan Zezeski void
mac_client_clear_flow_cb(mac_client_handle_t mch)175445948e49SRyan Zezeski mac_client_clear_flow_cb(mac_client_handle_t mch)
175545948e49SRyan Zezeski {
175645948e49SRyan Zezeski mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
175745948e49SRyan Zezeski flow_entry_t *flent = mcip->mci_flent;
175845948e49SRyan Zezeski
175945948e49SRyan Zezeski mutex_enter(&flent->fe_lock);
1760c61a1653SRyan Zezeski flent->fe_cb_fn = (flow_fn_t)mac_rx_def;
176145948e49SRyan Zezeski flent->fe_cb_arg1 = NULL;
176245948e49SRyan Zezeski flent->fe_cb_arg2 = NULL;
176345948e49SRyan Zezeski flent->fe_flags |= FE_MC_NO_DATAPATH;
176445948e49SRyan Zezeski mutex_exit(&flent->fe_lock);
176545948e49SRyan Zezeski }
176645948e49SRyan Zezeski
176745948e49SRyan Zezeski /*
17680dc2366fSVenugopal Iyer * Export ddi interrupt handles from the HW ring to the pseudo ring and
17690dc2366fSVenugopal Iyer * setup the RX callback of the mac client which exclusively controls
17700dc2366fSVenugopal Iyer * HW ring.
1771da14cebeSEric Cheng */
1772da14cebeSEric Cheng void
mac_hwring_setup(mac_ring_handle_t hwrh,mac_resource_handle_t prh,mac_ring_handle_t pseudo_rh)17730dc2366fSVenugopal Iyer mac_hwring_setup(mac_ring_handle_t hwrh, mac_resource_handle_t prh,
17740dc2366fSVenugopal Iyer mac_ring_handle_t pseudo_rh)
1775da14cebeSEric Cheng {
1776da14cebeSEric Cheng mac_ring_t *hw_ring = (mac_ring_t *)hwrh;
17770dc2366fSVenugopal Iyer mac_ring_t *pseudo_ring;
1778da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs = hw_ring->mr_srs;
1779da14cebeSEric Cheng
17800dc2366fSVenugopal Iyer if (pseudo_rh != NULL) {
17810dc2366fSVenugopal Iyer pseudo_ring = (mac_ring_t *)pseudo_rh;
17820dc2366fSVenugopal Iyer /* Export the ddi handles to pseudo ring */
17830dc2366fSVenugopal Iyer pseudo_ring->mr_info.mri_intr.mi_ddi_handle =
17840dc2366fSVenugopal Iyer hw_ring->mr_info.mri_intr.mi_ddi_handle;
17850dc2366fSVenugopal Iyer pseudo_ring->mr_info.mri_intr.mi_ddi_shared =
17860dc2366fSVenugopal Iyer hw_ring->mr_info.mri_intr.mi_ddi_shared;
17870dc2366fSVenugopal Iyer /*
17880dc2366fSVenugopal Iyer * Save a pointer to pseudo ring in the hw ring. If
17890dc2366fSVenugopal Iyer * interrupt handle changes, the hw ring will be
17900dc2366fSVenugopal Iyer * notified of the change (see mac_ring_intr_set())
17910dc2366fSVenugopal Iyer * and the appropriate change has to be made to
17920dc2366fSVenugopal Iyer * the pseudo ring that has exported the ddi handle.
17930dc2366fSVenugopal Iyer */
17940dc2366fSVenugopal Iyer hw_ring->mr_prh = pseudo_rh;
17950dc2366fSVenugopal Iyer }
17960dc2366fSVenugopal Iyer
17970dc2366fSVenugopal Iyer if (hw_ring->mr_type == MAC_RING_TYPE_RX) {
17980dc2366fSVenugopal Iyer ASSERT(!(mac_srs->srs_type & SRST_TX));
1799da14cebeSEric Cheng mac_srs->srs_mrh = prh;
1800da14cebeSEric Cheng mac_srs->srs_rx.sr_lower_proc = mac_hwrings_rx_process;
1801da14cebeSEric Cheng }
18020dc2366fSVenugopal Iyer }
1803da14cebeSEric Cheng
1804da14cebeSEric Cheng void
mac_hwring_teardown(mac_ring_handle_t hwrh)1805da14cebeSEric Cheng mac_hwring_teardown(mac_ring_handle_t hwrh)
1806da14cebeSEric Cheng {
1807da14cebeSEric Cheng mac_ring_t *hw_ring = (mac_ring_t *)hwrh;
18080dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
1809da14cebeSEric Cheng
18100dc2366fSVenugopal Iyer if (hw_ring == NULL)
18110dc2366fSVenugopal Iyer return;
18120dc2366fSVenugopal Iyer hw_ring->mr_prh = NULL;
18130dc2366fSVenugopal Iyer if (hw_ring->mr_type == MAC_RING_TYPE_RX) {
18140dc2366fSVenugopal Iyer mac_srs = hw_ring->mr_srs;
18150dc2366fSVenugopal Iyer ASSERT(!(mac_srs->srs_type & SRST_TX));
1816da14cebeSEric Cheng mac_srs->srs_rx.sr_lower_proc = mac_rx_srs_process;
1817da14cebeSEric Cheng mac_srs->srs_mrh = NULL;
1818da14cebeSEric Cheng }
18190dc2366fSVenugopal Iyer }
1820da14cebeSEric Cheng
1821da14cebeSEric Cheng int
mac_hwring_disable_intr(mac_ring_handle_t rh)1822da14cebeSEric Cheng mac_hwring_disable_intr(mac_ring_handle_t rh)
1823da14cebeSEric Cheng {
1824da14cebeSEric Cheng mac_ring_t *rr_ring = (mac_ring_t *)rh;
1825da14cebeSEric Cheng mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
1826da14cebeSEric Cheng
1827da14cebeSEric Cheng return (intr->mi_disable(intr->mi_handle));
1828da14cebeSEric Cheng }
1829da14cebeSEric Cheng
1830da14cebeSEric Cheng int
mac_hwring_enable_intr(mac_ring_handle_t rh)1831da14cebeSEric Cheng mac_hwring_enable_intr(mac_ring_handle_t rh)
1832da14cebeSEric Cheng {
1833da14cebeSEric Cheng mac_ring_t *rr_ring = (mac_ring_t *)rh;
1834da14cebeSEric Cheng mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
1835da14cebeSEric Cheng
1836da14cebeSEric Cheng return (intr->mi_enable(intr->mi_handle));
1837da14cebeSEric Cheng }
1838da14cebeSEric Cheng
183945948e49SRyan Zezeski /*
184045948e49SRyan Zezeski * Start the HW ring pointed to by rh.
184145948e49SRyan Zezeski *
184245948e49SRyan Zezeski * This is used by special MAC clients that are MAC themselves and
184345948e49SRyan Zezeski * need to exert control over the underlying HW rings of the NIC.
184445948e49SRyan Zezeski */
1845da14cebeSEric Cheng int
mac_hwring_start(mac_ring_handle_t rh)1846da14cebeSEric Cheng mac_hwring_start(mac_ring_handle_t rh)
1847da14cebeSEric Cheng {
1848da14cebeSEric Cheng mac_ring_t *rr_ring = (mac_ring_t *)rh;
184945948e49SRyan Zezeski int rv = 0;
185045948e49SRyan Zezeski
185145948e49SRyan Zezeski if (rr_ring->mr_state != MR_INUSE)
185245948e49SRyan Zezeski rv = mac_start_ring(rr_ring);
185345948e49SRyan Zezeski
185445948e49SRyan Zezeski return (rv);
185545948e49SRyan Zezeski }
185645948e49SRyan Zezeski
185745948e49SRyan Zezeski /*
185845948e49SRyan Zezeski * Stop the HW ring pointed to by rh. Also see mac_hwring_start().
185945948e49SRyan Zezeski */
186045948e49SRyan Zezeski void
mac_hwring_stop(mac_ring_handle_t rh)186145948e49SRyan Zezeski mac_hwring_stop(mac_ring_handle_t rh)
186245948e49SRyan Zezeski {
186345948e49SRyan Zezeski mac_ring_t *rr_ring = (mac_ring_t *)rh;
186445948e49SRyan Zezeski
186545948e49SRyan Zezeski if (rr_ring->mr_state != MR_FREE)
186645948e49SRyan Zezeski mac_stop_ring(rr_ring);
186745948e49SRyan Zezeski }
186845948e49SRyan Zezeski
186945948e49SRyan Zezeski /*
187045948e49SRyan Zezeski * Remove the quiesced flag from the HW ring pointed to by rh.
187145948e49SRyan Zezeski *
187245948e49SRyan Zezeski * This is used by special MAC clients that are MAC themselves and
187345948e49SRyan Zezeski * need to exert control over the underlying HW rings of the NIC.
187445948e49SRyan Zezeski */
187545948e49SRyan Zezeski int
mac_hwring_activate(mac_ring_handle_t rh)187645948e49SRyan Zezeski mac_hwring_activate(mac_ring_handle_t rh)
187745948e49SRyan Zezeski {
187845948e49SRyan Zezeski mac_ring_t *rr_ring = (mac_ring_t *)rh;
1879da14cebeSEric Cheng
1880da14cebeSEric Cheng MAC_RING_UNMARK(rr_ring, MR_QUIESCE);
1881da14cebeSEric Cheng return (0);
1882da14cebeSEric Cheng }
1883da14cebeSEric Cheng
188445948e49SRyan Zezeski /*
188545948e49SRyan Zezeski * Quiesce the HW ring pointed to by rh. Also see mac_hwring_activate().
188645948e49SRyan Zezeski */
1887da14cebeSEric Cheng void
mac_hwring_quiesce(mac_ring_handle_t rh)188845948e49SRyan Zezeski mac_hwring_quiesce(mac_ring_handle_t rh)
1889da14cebeSEric Cheng {
1890da14cebeSEric Cheng mac_ring_t *rr_ring = (mac_ring_t *)rh;
1891da14cebeSEric Cheng
1892da14cebeSEric Cheng mac_rx_ring_quiesce(rr_ring, MR_QUIESCE);
1893da14cebeSEric Cheng }
1894da14cebeSEric Cheng
1895da14cebeSEric Cheng mblk_t *
mac_hwring_poll(mac_ring_handle_t rh,int bytes_to_pickup)1896da14cebeSEric Cheng mac_hwring_poll(mac_ring_handle_t rh, int bytes_to_pickup)
1897da14cebeSEric Cheng {
1898da14cebeSEric Cheng mac_ring_t *rr_ring = (mac_ring_t *)rh;
1899da14cebeSEric Cheng mac_ring_info_t *info = &rr_ring->mr_info;
1900da14cebeSEric Cheng
1901da14cebeSEric Cheng return (info->mri_poll(info->mri_driver, bytes_to_pickup));
1902da14cebeSEric Cheng }
1903da14cebeSEric Cheng
190463f531d1SSriharsha Basavapatna /*
19050dc2366fSVenugopal Iyer * Send packets through a selected tx ring.
190663f531d1SSriharsha Basavapatna */
190763f531d1SSriharsha Basavapatna mblk_t *
mac_hwring_tx(mac_ring_handle_t rh,mblk_t * mp)190863f531d1SSriharsha Basavapatna mac_hwring_tx(mac_ring_handle_t rh, mblk_t *mp)
190963f531d1SSriharsha Basavapatna {
191063f531d1SSriharsha Basavapatna mac_ring_t *ring = (mac_ring_t *)rh;
191163f531d1SSriharsha Basavapatna mac_ring_info_t *info = &ring->mr_info;
191263f531d1SSriharsha Basavapatna
19134eaa4710SRishi Srivatsavai ASSERT(ring->mr_type == MAC_RING_TYPE_TX &&
19144eaa4710SRishi Srivatsavai ring->mr_state >= MR_INUSE);
191563f531d1SSriharsha Basavapatna return (info->mri_tx(info->mri_driver, mp));
191663f531d1SSriharsha Basavapatna }
191763f531d1SSriharsha Basavapatna
19180dc2366fSVenugopal Iyer /*
19190dc2366fSVenugopal Iyer * Query stats for a particular rx/tx ring
19200dc2366fSVenugopal Iyer */
19210dc2366fSVenugopal Iyer int
mac_hwring_getstat(mac_ring_handle_t rh,uint_t stat,uint64_t * val)19220dc2366fSVenugopal Iyer mac_hwring_getstat(mac_ring_handle_t rh, uint_t stat, uint64_t *val)
19230dc2366fSVenugopal Iyer {
19240dc2366fSVenugopal Iyer mac_ring_t *ring = (mac_ring_t *)rh;
19250dc2366fSVenugopal Iyer mac_ring_info_t *info = &ring->mr_info;
19260dc2366fSVenugopal Iyer
19270dc2366fSVenugopal Iyer return (info->mri_stat(info->mri_driver, stat, val));
19280dc2366fSVenugopal Iyer }
19290dc2366fSVenugopal Iyer
19300dc2366fSVenugopal Iyer /*
19310dc2366fSVenugopal Iyer * Private function that is only used by aggr to send packets through
19320dc2366fSVenugopal Iyer * a port/Tx ring. Since aggr exposes a pseudo Tx ring even for ports
19330dc2366fSVenugopal Iyer * that does not expose Tx rings, aggr_ring_tx() entry point needs
19340dc2366fSVenugopal Iyer * access to mac_impl_t to send packets through m_tx() entry point.
19350dc2366fSVenugopal Iyer * It accomplishes this by calling mac_hwring_send_priv() function.
19360dc2366fSVenugopal Iyer */
19370dc2366fSVenugopal Iyer mblk_t *
mac_hwring_send_priv(mac_client_handle_t mch,mac_ring_handle_t rh,mblk_t * mp)19380dc2366fSVenugopal Iyer mac_hwring_send_priv(mac_client_handle_t mch, mac_ring_handle_t rh, mblk_t *mp)
19390dc2366fSVenugopal Iyer {
19400dc2366fSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
19410dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
19420dc2366fSVenugopal Iyer
1943c61a1653SRyan Zezeski return (mac_provider_tx(mip, rh, mp, mcip));
19440dc2366fSVenugopal Iyer }
19450dc2366fSVenugopal Iyer
194609b7f21aSRobert Mustacchi /*
194709b7f21aSRobert Mustacchi * Private function that is only used by aggr to update the default transmission
194809b7f21aSRobert Mustacchi * ring. Because aggr exposes a pseudo Tx ring even for ports that may
194909b7f21aSRobert Mustacchi * temporarily be down, it may need to update the default ring that is used by
195009b7f21aSRobert Mustacchi * MAC such that it refers to a link that can actively be used to send traffic.
195109b7f21aSRobert Mustacchi * Note that this is different from the case where the port has been removed
195209b7f21aSRobert Mustacchi * from the group. In those cases, all of the rings will be torn down because
195309b7f21aSRobert Mustacchi * the ring will no longer exist. It's important to give aggr a case where the
195409b7f21aSRobert Mustacchi * rings can still exist such that it may be able to continue to send LACP PDUs
195509b7f21aSRobert Mustacchi * to potentially restore the link.
195609b7f21aSRobert Mustacchi */
195709b7f21aSRobert Mustacchi void
mac_hwring_set_default(mac_handle_t mh,mac_ring_handle_t rh)195809b7f21aSRobert Mustacchi mac_hwring_set_default(mac_handle_t mh, mac_ring_handle_t rh)
195909b7f21aSRobert Mustacchi {
196009b7f21aSRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
196109b7f21aSRobert Mustacchi mac_ring_t *ring = (mac_ring_t *)rh;
196209b7f21aSRobert Mustacchi
196309b7f21aSRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
196409b7f21aSRobert Mustacchi VERIFY(mip->mi_state_flags & MIS_IS_AGGR);
196509b7f21aSRobert Mustacchi
196699ad48a4SRyan Zezeski /*
196799ad48a4SRyan Zezeski * We used to condition this assignment on the ring's
196899ad48a4SRyan Zezeski * 'mr_state' being one of 'MR_INUSE'. However, there are
196999ad48a4SRyan Zezeski * cases where this is called before the ring has any active
197099ad48a4SRyan Zezeski * clients, and therefore is not marked as in use. Since the
197199ad48a4SRyan Zezeski * sole purpose of this function is for aggr to make sure
197299ad48a4SRyan Zezeski * 'mi_default_tx_ring' matches 'lg_tx_ports[0]', its
197399ad48a4SRyan Zezeski * imperative that we update its value regardless of ring
197499ad48a4SRyan Zezeski * state. Otherwise, we can end up in a state where
197599ad48a4SRyan Zezeski * 'mi_default_tx_ring' points to a pseudo ring of a downed
197699ad48a4SRyan Zezeski * port, even when 'lg_tx_ports[0]' points to a port that is
197799ad48a4SRyan Zezeski * up.
197899ad48a4SRyan Zezeski */
197909b7f21aSRobert Mustacchi mip->mi_default_tx_ring = rh;
198009b7f21aSRobert Mustacchi }
198109b7f21aSRobert Mustacchi
1982da14cebeSEric Cheng int
mac_hwgroup_addmac(mac_group_handle_t gh,const uint8_t * addr)1983da14cebeSEric Cheng mac_hwgroup_addmac(mac_group_handle_t gh, const uint8_t *addr)
1984da14cebeSEric Cheng {
1985da14cebeSEric Cheng mac_group_t *group = (mac_group_t *)gh;
1986da14cebeSEric Cheng
1987da14cebeSEric Cheng return (mac_group_addmac(group, addr));
1988da14cebeSEric Cheng }
1989da14cebeSEric Cheng
1990da14cebeSEric Cheng int
mac_hwgroup_remmac(mac_group_handle_t gh,const uint8_t * addr)1991da14cebeSEric Cheng mac_hwgroup_remmac(mac_group_handle_t gh, const uint8_t *addr)
1992da14cebeSEric Cheng {
1993da14cebeSEric Cheng mac_group_t *group = (mac_group_t *)gh;
1994da14cebeSEric Cheng
1995da14cebeSEric Cheng return (mac_group_remmac(group, addr));
1996da14cebeSEric Cheng }
1997da14cebeSEric Cheng
1998da14cebeSEric Cheng /*
199984de666eSRyan Zezeski * Program the group's HW VLAN filter if it has such support.
200084de666eSRyan Zezeski * Otherwise, the group will implicitly accept tagged traffic and
200184de666eSRyan Zezeski * there is nothing to do.
200284de666eSRyan Zezeski */
200384de666eSRyan Zezeski int
mac_hwgroup_addvlan(mac_group_handle_t gh,uint16_t vid)200484de666eSRyan Zezeski mac_hwgroup_addvlan(mac_group_handle_t gh, uint16_t vid)
200584de666eSRyan Zezeski {
200684de666eSRyan Zezeski mac_group_t *group = (mac_group_t *)gh;
200784de666eSRyan Zezeski
200884de666eSRyan Zezeski if (!MAC_GROUP_HW_VLAN(group))
200984de666eSRyan Zezeski return (0);
201084de666eSRyan Zezeski
201184de666eSRyan Zezeski return (mac_group_addvlan(group, vid));
201284de666eSRyan Zezeski }
201384de666eSRyan Zezeski
201484de666eSRyan Zezeski int
mac_hwgroup_remvlan(mac_group_handle_t gh,uint16_t vid)201584de666eSRyan Zezeski mac_hwgroup_remvlan(mac_group_handle_t gh, uint16_t vid)
201684de666eSRyan Zezeski {
201784de666eSRyan Zezeski mac_group_t *group = (mac_group_t *)gh;
201884de666eSRyan Zezeski
201984de666eSRyan Zezeski if (!MAC_GROUP_HW_VLAN(group))
202084de666eSRyan Zezeski return (0);
202184de666eSRyan Zezeski
202284de666eSRyan Zezeski return (mac_group_remvlan(group, vid));
202384de666eSRyan Zezeski }
202484de666eSRyan Zezeski
202584de666eSRyan Zezeski /*
202684de666eSRyan Zezeski * Determine if a MAC has HW VLAN support. This is a private API
202784de666eSRyan Zezeski * consumed by aggr. In the future it might be nice to have a bitfield
202884de666eSRyan Zezeski * in mac_capab_rings_t to track which forms of HW filtering are
202984de666eSRyan Zezeski * supported by the MAC.
203084de666eSRyan Zezeski */
203184de666eSRyan Zezeski boolean_t
mac_has_hw_vlan(mac_handle_t mh)203284de666eSRyan Zezeski mac_has_hw_vlan(mac_handle_t mh)
203384de666eSRyan Zezeski {
203484de666eSRyan Zezeski mac_impl_t *mip = (mac_impl_t *)mh;
203584de666eSRyan Zezeski
203684de666eSRyan Zezeski return (MAC_GROUP_HW_VLAN(mip->mi_rx_groups));
203784de666eSRyan Zezeski }
203884de666eSRyan Zezeski
203984de666eSRyan Zezeski /*
204045948e49SRyan Zezeski * Get the number of Rx HW groups on this MAC.
204145948e49SRyan Zezeski */
204245948e49SRyan Zezeski uint_t
mac_get_num_rx_groups(mac_handle_t mh)204345948e49SRyan Zezeski mac_get_num_rx_groups(mac_handle_t mh)
204445948e49SRyan Zezeski {
204545948e49SRyan Zezeski mac_impl_t *mip = (mac_impl_t *)mh;
204645948e49SRyan Zezeski
204745948e49SRyan Zezeski ASSERT(MAC_PERIM_HELD(mh));
204845948e49SRyan Zezeski return (mip->mi_rx_group_count);
204945948e49SRyan Zezeski }
205045948e49SRyan Zezeski
205145948e49SRyan Zezeski int
mac_set_promisc(mac_handle_t mh,boolean_t value)205245948e49SRyan Zezeski mac_set_promisc(mac_handle_t mh, boolean_t value)
205345948e49SRyan Zezeski {
205445948e49SRyan Zezeski mac_impl_t *mip = (mac_impl_t *)mh;
205545948e49SRyan Zezeski
205645948e49SRyan Zezeski ASSERT(MAC_PERIM_HELD(mh));
205745948e49SRyan Zezeski return (i_mac_promisc_set(mip, value));
205845948e49SRyan Zezeski }
205945948e49SRyan Zezeski
206045948e49SRyan Zezeski /*
2061da14cebeSEric Cheng * Set the RX group to be shared/reserved. Note that the group must be
2062da14cebeSEric Cheng * started/stopped outside of this function.
2063da14cebeSEric Cheng */
2064da14cebeSEric Cheng void
mac_set_group_state(mac_group_t * grp,mac_group_state_t state)20650dc2366fSVenugopal Iyer mac_set_group_state(mac_group_t *grp, mac_group_state_t state)
2066da14cebeSEric Cheng {
2067da14cebeSEric Cheng /*
2068da14cebeSEric Cheng * If there is no change in the group state, just return.
2069da14cebeSEric Cheng */
2070da14cebeSEric Cheng if (grp->mrg_state == state)
2071da14cebeSEric Cheng return;
2072da14cebeSEric Cheng
2073da14cebeSEric Cheng switch (state) {
2074da14cebeSEric Cheng case MAC_GROUP_STATE_RESERVED:
2075da14cebeSEric Cheng /*
2076da14cebeSEric Cheng * Successfully reserved the group.
2077da14cebeSEric Cheng *
2078da14cebeSEric Cheng * Given that there is an exclusive client controlling this
2079da14cebeSEric Cheng * group, we enable the group level polling when available,
2080da14cebeSEric Cheng * so that SRSs get to turn on/off individual rings they's
2081da14cebeSEric Cheng * assigned to.
2082da14cebeSEric Cheng */
2083da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(grp->mrg_mh));
2084da14cebeSEric Cheng
20850dc2366fSVenugopal Iyer if (grp->mrg_type == MAC_RING_TYPE_RX &&
20860dc2366fSVenugopal Iyer GROUP_INTR_DISABLE_FUNC(grp) != NULL) {
2087da14cebeSEric Cheng GROUP_INTR_DISABLE_FUNC(grp)(GROUP_INTR_HANDLE(grp));
20880dc2366fSVenugopal Iyer }
2089da14cebeSEric Cheng break;
2090da14cebeSEric Cheng
2091da14cebeSEric Cheng case MAC_GROUP_STATE_SHARED:
2092da14cebeSEric Cheng /*
2093da14cebeSEric Cheng * Set all rings of this group to software classified.
2094da14cebeSEric Cheng * If the group has an overriding interrupt, then re-enable it.
2095da14cebeSEric Cheng */
2096da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(grp->mrg_mh));
2097da14cebeSEric Cheng
20980dc2366fSVenugopal Iyer if (grp->mrg_type == MAC_RING_TYPE_RX &&
20990dc2366fSVenugopal Iyer GROUP_INTR_ENABLE_FUNC(grp) != NULL) {
2100da14cebeSEric Cheng GROUP_INTR_ENABLE_FUNC(grp)(GROUP_INTR_HANDLE(grp));
21010dc2366fSVenugopal Iyer }
2102da14cebeSEric Cheng /* The ring is not available for reservations any more */
2103da14cebeSEric Cheng break;
2104da14cebeSEric Cheng
2105da14cebeSEric Cheng case MAC_GROUP_STATE_REGISTERED:
2106da14cebeSEric Cheng /* Also callable from mac_register, perim is not held */
2107da14cebeSEric Cheng break;
2108da14cebeSEric Cheng
2109da14cebeSEric Cheng default:
2110da14cebeSEric Cheng ASSERT(B_FALSE);
2111da14cebeSEric Cheng break;
2112da14cebeSEric Cheng }
2113da14cebeSEric Cheng
2114da14cebeSEric Cheng grp->mrg_state = state;
2115da14cebeSEric Cheng }
2116da14cebeSEric Cheng
2117da14cebeSEric Cheng /*
2118da14cebeSEric Cheng * Quiesce future hardware classified packets for the specified Rx ring
2119da14cebeSEric Cheng */
2120da14cebeSEric Cheng static void
mac_rx_ring_quiesce(mac_ring_t * rx_ring,uint_t ring_flag)2121da14cebeSEric Cheng mac_rx_ring_quiesce(mac_ring_t *rx_ring, uint_t ring_flag)
2122da14cebeSEric Cheng {
2123da14cebeSEric Cheng ASSERT(rx_ring->mr_classify_type == MAC_HW_CLASSIFIER);
2124da14cebeSEric Cheng ASSERT(ring_flag == MR_CONDEMNED || ring_flag == MR_QUIESCE);
2125da14cebeSEric Cheng
2126da14cebeSEric Cheng mutex_enter(&rx_ring->mr_lock);
2127da14cebeSEric Cheng rx_ring->mr_flag |= ring_flag;
2128da14cebeSEric Cheng while (rx_ring->mr_refcnt != 0)
2129da14cebeSEric Cheng cv_wait(&rx_ring->mr_cv, &rx_ring->mr_lock);
2130da14cebeSEric Cheng mutex_exit(&rx_ring->mr_lock);
2131da14cebeSEric Cheng }
2132da14cebeSEric Cheng
2133da14cebeSEric Cheng /*
2134da14cebeSEric Cheng * Please see mac_tx for details about the per cpu locking scheme
2135da14cebeSEric Cheng */
2136da14cebeSEric Cheng static void
mac_tx_lock_all(mac_client_impl_t * mcip)2137da14cebeSEric Cheng mac_tx_lock_all(mac_client_impl_t *mcip)
2138da14cebeSEric Cheng {
2139da14cebeSEric Cheng int i;
2140da14cebeSEric Cheng
2141da14cebeSEric Cheng for (i = 0; i <= mac_tx_percpu_cnt; i++)
2142da14cebeSEric Cheng mutex_enter(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2143da14cebeSEric Cheng }
2144da14cebeSEric Cheng
2145da14cebeSEric Cheng static void
mac_tx_unlock_all(mac_client_impl_t * mcip)2146da14cebeSEric Cheng mac_tx_unlock_all(mac_client_impl_t *mcip)
2147da14cebeSEric Cheng {
2148da14cebeSEric Cheng int i;
2149da14cebeSEric Cheng
2150da14cebeSEric Cheng for (i = mac_tx_percpu_cnt; i >= 0; i--)
2151da14cebeSEric Cheng mutex_exit(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2152da14cebeSEric Cheng }
2153da14cebeSEric Cheng
2154da14cebeSEric Cheng static void
mac_tx_unlock_allbutzero(mac_client_impl_t * mcip)2155da14cebeSEric Cheng mac_tx_unlock_allbutzero(mac_client_impl_t *mcip)
2156da14cebeSEric Cheng {
2157da14cebeSEric Cheng int i;
2158da14cebeSEric Cheng
2159da14cebeSEric Cheng for (i = mac_tx_percpu_cnt; i > 0; i--)
2160da14cebeSEric Cheng mutex_exit(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2161da14cebeSEric Cheng }
2162da14cebeSEric Cheng
2163da14cebeSEric Cheng static int
mac_tx_sum_refcnt(mac_client_impl_t * mcip)2164da14cebeSEric Cheng mac_tx_sum_refcnt(mac_client_impl_t *mcip)
2165da14cebeSEric Cheng {
2166da14cebeSEric Cheng int i;
2167da14cebeSEric Cheng int refcnt = 0;
2168da14cebeSEric Cheng
2169da14cebeSEric Cheng for (i = 0; i <= mac_tx_percpu_cnt; i++)
2170da14cebeSEric Cheng refcnt += mcip->mci_tx_pcpu[i].pcpu_tx_refcnt;
2171da14cebeSEric Cheng
2172da14cebeSEric Cheng return (refcnt);
2173da14cebeSEric Cheng }
2174da14cebeSEric Cheng
2175da14cebeSEric Cheng /*
2176da14cebeSEric Cheng * Stop future Tx packets coming down from the client in preparation for
2177da14cebeSEric Cheng * quiescing the Tx side. This is needed for dynamic reclaim and reassignment
2178da14cebeSEric Cheng * of rings between clients
2179da14cebeSEric Cheng */
2180da14cebeSEric Cheng void
mac_tx_client_block(mac_client_impl_t * mcip)2181da14cebeSEric Cheng mac_tx_client_block(mac_client_impl_t *mcip)
2182da14cebeSEric Cheng {
2183da14cebeSEric Cheng mac_tx_lock_all(mcip);
2184da14cebeSEric Cheng mcip->mci_tx_flag |= MCI_TX_QUIESCE;
2185da14cebeSEric Cheng while (mac_tx_sum_refcnt(mcip) != 0) {
2186da14cebeSEric Cheng mac_tx_unlock_allbutzero(mcip);
2187da14cebeSEric Cheng cv_wait(&mcip->mci_tx_cv, &mcip->mci_tx_pcpu[0].pcpu_tx_lock);
2188da14cebeSEric Cheng mutex_exit(&mcip->mci_tx_pcpu[0].pcpu_tx_lock);
2189da14cebeSEric Cheng mac_tx_lock_all(mcip);
2190da14cebeSEric Cheng }
2191da14cebeSEric Cheng mac_tx_unlock_all(mcip);
2192da14cebeSEric Cheng }
2193da14cebeSEric Cheng
2194da14cebeSEric Cheng void
mac_tx_client_unblock(mac_client_impl_t * mcip)2195da14cebeSEric Cheng mac_tx_client_unblock(mac_client_impl_t *mcip)
2196da14cebeSEric Cheng {
2197da14cebeSEric Cheng mac_tx_lock_all(mcip);
2198da14cebeSEric Cheng mcip->mci_tx_flag &= ~MCI_TX_QUIESCE;
2199da14cebeSEric Cheng mac_tx_unlock_all(mcip);
2200ae6aa22aSVenugopal Iyer /*
2201ae6aa22aSVenugopal Iyer * We may fail to disable flow control for the last MAC_NOTE_TX
2202ae6aa22aSVenugopal Iyer * notification because the MAC client is quiesced. Send the
2203ae6aa22aSVenugopal Iyer * notification again.
2204ae6aa22aSVenugopal Iyer */
2205ae6aa22aSVenugopal Iyer i_mac_notify(mcip->mci_mip, MAC_NOTE_TX);
2206da14cebeSEric Cheng }
2207da14cebeSEric Cheng
2208da14cebeSEric Cheng /*
2209da14cebeSEric Cheng * Wait for an SRS to quiesce. The SRS worker will signal us when the
2210da14cebeSEric Cheng * quiesce is done.
2211da14cebeSEric Cheng */
2212da14cebeSEric Cheng static void
mac_srs_quiesce_wait(mac_soft_ring_set_t * srs,uint_t srs_flag)2213da14cebeSEric Cheng mac_srs_quiesce_wait(mac_soft_ring_set_t *srs, uint_t srs_flag)
2214da14cebeSEric Cheng {
2215da14cebeSEric Cheng mutex_enter(&srs->srs_lock);
2216da14cebeSEric Cheng while (!(srs->srs_state & srs_flag))
2217da14cebeSEric Cheng cv_wait(&srs->srs_quiesce_done_cv, &srs->srs_lock);
2218da14cebeSEric Cheng mutex_exit(&srs->srs_lock);
2219da14cebeSEric Cheng }
2220da14cebeSEric Cheng
2221da14cebeSEric Cheng /*
2222da14cebeSEric Cheng * Quiescing an Rx SRS is achieved by the following sequence. The protocol
2223da14cebeSEric Cheng * works bottom up by cutting off packet flow from the bottommost point in the
2224da14cebeSEric Cheng * mac, then the SRS, and then the soft rings. There are 2 use cases of this
2225da14cebeSEric Cheng * mechanism. One is a temporary quiesce of the SRS, such as say while changing
2226da14cebeSEric Cheng * the Rx callbacks. Another use case is Rx SRS teardown. In the former case
2227da14cebeSEric Cheng * the QUIESCE prefix/suffix is used and in the latter the CONDEMNED is used
2228da14cebeSEric Cheng * for the SRS and MR flags. In the former case the threads pause waiting for
2229da14cebeSEric Cheng * a restart, while in the latter case the threads exit. The Tx SRS teardown
2230da14cebeSEric Cheng * is also mostly similar to the above.
2231da14cebeSEric Cheng *
2232da14cebeSEric Cheng * 1. Stop future hardware classified packets at the lowest level in the mac.
2233da14cebeSEric Cheng * Remove any hardware classification rule (CONDEMNED case) and mark the
2234da14cebeSEric Cheng * rings as CONDEMNED or QUIESCE as appropriate. This prevents the mr_refcnt
2235da14cebeSEric Cheng * from increasing. Upcalls from the driver that come through hardware
2236da14cebeSEric Cheng * classification will be dropped in mac_rx from now on. Then we wait for
2237da14cebeSEric Cheng * the mr_refcnt to drop to zero. When the mr_refcnt reaches zero we are
2238da14cebeSEric Cheng * sure there aren't any upcall threads from the driver through hardware
2239da14cebeSEric Cheng * classification. In the case of SRS teardown we also remove the
2240da14cebeSEric Cheng * classification rule in the driver.
2241da14cebeSEric Cheng *
2242da14cebeSEric Cheng * 2. Stop future software classified packets by marking the flow entry with
2243da14cebeSEric Cheng * FE_QUIESCE or FE_CONDEMNED as appropriate which prevents the refcnt from
2244da14cebeSEric Cheng * increasing. We also remove the flow entry from the table in the latter
2245da14cebeSEric Cheng * case. Then wait for the fe_refcnt to reach an appropriate quiescent value
2246da14cebeSEric Cheng * that indicates there aren't any active threads using that flow entry.
2247da14cebeSEric Cheng *
2248da14cebeSEric Cheng * 3. Quiesce the SRS and softrings by signaling the SRS. The SRS poll thread,
2249da14cebeSEric Cheng * SRS worker thread, and the soft ring threads are quiesced in sequence
2250da14cebeSEric Cheng * with the SRS worker thread serving as a master controller. This
2251da14cebeSEric Cheng * mechansim is explained in mac_srs_worker_quiesce().
2252da14cebeSEric Cheng *
2253da14cebeSEric Cheng * The restart mechanism to reactivate the SRS and softrings is explained
2254da14cebeSEric Cheng * in mac_srs_worker_restart(). Here we just signal the SRS worker to start the
2255da14cebeSEric Cheng * restart sequence.
2256da14cebeSEric Cheng */
2257da14cebeSEric Cheng void
mac_rx_srs_quiesce(mac_soft_ring_set_t * srs,uint_t srs_quiesce_flag)2258da14cebeSEric Cheng mac_rx_srs_quiesce(mac_soft_ring_set_t *srs, uint_t srs_quiesce_flag)
2259da14cebeSEric Cheng {
2260da14cebeSEric Cheng flow_entry_t *flent = srs->srs_flent;
2261da14cebeSEric Cheng uint_t mr_flag, srs_done_flag;
2262da14cebeSEric Cheng
2263da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)FLENT_TO_MIP(flent)));
2264da14cebeSEric Cheng ASSERT(!(srs->srs_type & SRST_TX));
2265da14cebeSEric Cheng
2266da14cebeSEric Cheng if (srs_quiesce_flag == SRS_CONDEMNED) {
2267da14cebeSEric Cheng mr_flag = MR_CONDEMNED;
2268da14cebeSEric Cheng srs_done_flag = SRS_CONDEMNED_DONE;
2269da14cebeSEric Cheng if (srs->srs_type & SRST_CLIENT_POLL_ENABLED)
2270da14cebeSEric Cheng mac_srs_client_poll_disable(srs->srs_mcip, srs);
2271da14cebeSEric Cheng } else {
2272da14cebeSEric Cheng ASSERT(srs_quiesce_flag == SRS_QUIESCE);
2273da14cebeSEric Cheng mr_flag = MR_QUIESCE;
2274da14cebeSEric Cheng srs_done_flag = SRS_QUIESCE_DONE;
2275da14cebeSEric Cheng if (srs->srs_type & SRST_CLIENT_POLL_ENABLED)
2276da14cebeSEric Cheng mac_srs_client_poll_quiesce(srs->srs_mcip, srs);
2277da14cebeSEric Cheng }
2278da14cebeSEric Cheng
2279da14cebeSEric Cheng if (srs->srs_ring != NULL) {
2280da14cebeSEric Cheng mac_rx_ring_quiesce(srs->srs_ring, mr_flag);
2281da14cebeSEric Cheng } else {
2282da14cebeSEric Cheng /*
2283da14cebeSEric Cheng * SRS is driven by software classification. In case
2284da14cebeSEric Cheng * of CONDEMNED, the top level teardown functions will
2285da14cebeSEric Cheng * deal with flow removal.
2286da14cebeSEric Cheng */
2287da14cebeSEric Cheng if (srs_quiesce_flag != SRS_CONDEMNED) {
2288da14cebeSEric Cheng FLOW_MARK(flent, FE_QUIESCE);
2289da14cebeSEric Cheng mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
2290da14cebeSEric Cheng }
2291da14cebeSEric Cheng }
2292da14cebeSEric Cheng
2293da14cebeSEric Cheng /*
2294da14cebeSEric Cheng * Signal the SRS to quiesce itself, and then cv_wait for the
2295da14cebeSEric Cheng * SRS quiesce to complete. The SRS worker thread will wake us
2296da14cebeSEric Cheng * up when the quiesce is complete
2297da14cebeSEric Cheng */
2298da14cebeSEric Cheng mac_srs_signal(srs, srs_quiesce_flag);
2299da14cebeSEric Cheng mac_srs_quiesce_wait(srs, srs_done_flag);
2300da14cebeSEric Cheng }
2301da14cebeSEric Cheng
2302da14cebeSEric Cheng /*
2303da14cebeSEric Cheng * Remove an SRS.
2304da14cebeSEric Cheng */
2305da14cebeSEric Cheng void
mac_rx_srs_remove(mac_soft_ring_set_t * srs)2306da14cebeSEric Cheng mac_rx_srs_remove(mac_soft_ring_set_t *srs)
2307da14cebeSEric Cheng {
2308da14cebeSEric Cheng flow_entry_t *flent = srs->srs_flent;
2309da14cebeSEric Cheng int i;
2310da14cebeSEric Cheng
2311da14cebeSEric Cheng mac_rx_srs_quiesce(srs, SRS_CONDEMNED);
2312da14cebeSEric Cheng /*
2313da14cebeSEric Cheng * Locate and remove our entry in the fe_rx_srs[] array, and
2314da14cebeSEric Cheng * adjust the fe_rx_srs array entries and array count by
2315da14cebeSEric Cheng * moving the last entry into the vacated spot.
2316da14cebeSEric Cheng */
2317da14cebeSEric Cheng mutex_enter(&flent->fe_lock);
2318da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2319da14cebeSEric Cheng if (flent->fe_rx_srs[i] == srs)
2320da14cebeSEric Cheng break;
2321da14cebeSEric Cheng }
2322da14cebeSEric Cheng
2323da14cebeSEric Cheng ASSERT(i != 0 && i < flent->fe_rx_srs_cnt);
2324da14cebeSEric Cheng if (i != flent->fe_rx_srs_cnt - 1) {
2325da14cebeSEric Cheng flent->fe_rx_srs[i] =
2326da14cebeSEric Cheng flent->fe_rx_srs[flent->fe_rx_srs_cnt - 1];
2327da14cebeSEric Cheng i = flent->fe_rx_srs_cnt - 1;
2328da14cebeSEric Cheng }
2329da14cebeSEric Cheng
2330da14cebeSEric Cheng flent->fe_rx_srs[i] = NULL;
2331da14cebeSEric Cheng flent->fe_rx_srs_cnt--;
2332da14cebeSEric Cheng mutex_exit(&flent->fe_lock);
2333da14cebeSEric Cheng
2334da14cebeSEric Cheng mac_srs_free(srs);
2335da14cebeSEric Cheng }
2336da14cebeSEric Cheng
2337da14cebeSEric Cheng static void
mac_srs_clear_flag(mac_soft_ring_set_t * srs,uint_t flag)2338da14cebeSEric Cheng mac_srs_clear_flag(mac_soft_ring_set_t *srs, uint_t flag)
2339da14cebeSEric Cheng {
2340da14cebeSEric Cheng mutex_enter(&srs->srs_lock);
2341da14cebeSEric Cheng srs->srs_state &= ~flag;
2342da14cebeSEric Cheng mutex_exit(&srs->srs_lock);
2343da14cebeSEric Cheng }
2344da14cebeSEric Cheng
2345da14cebeSEric Cheng void
mac_rx_srs_restart(mac_soft_ring_set_t * srs)2346da14cebeSEric Cheng mac_rx_srs_restart(mac_soft_ring_set_t *srs)
2347da14cebeSEric Cheng {
2348da14cebeSEric Cheng flow_entry_t *flent = srs->srs_flent;
2349da14cebeSEric Cheng mac_ring_t *mr;
2350da14cebeSEric Cheng
2351da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)FLENT_TO_MIP(flent)));
2352da14cebeSEric Cheng ASSERT((srs->srs_type & SRST_TX) == 0);
2353da14cebeSEric Cheng
2354da14cebeSEric Cheng /*
2355da14cebeSEric Cheng * This handles a change in the number of SRSs between the quiesce and
2356da14cebeSEric Cheng * and restart operation of a flow.
2357da14cebeSEric Cheng */
2358da14cebeSEric Cheng if (!SRS_QUIESCED(srs))
2359da14cebeSEric Cheng return;
2360da14cebeSEric Cheng
2361da14cebeSEric Cheng /*
2362da14cebeSEric Cheng * Signal the SRS to restart itself. Wait for the restart to complete
2363da14cebeSEric Cheng * Note that we only restart the SRS if it is not marked as
2364da14cebeSEric Cheng * permanently quiesced.
2365da14cebeSEric Cheng */
2366da14cebeSEric Cheng if (!SRS_QUIESCED_PERMANENT(srs)) {
2367da14cebeSEric Cheng mac_srs_signal(srs, SRS_RESTART);
2368da14cebeSEric Cheng mac_srs_quiesce_wait(srs, SRS_RESTART_DONE);
2369da14cebeSEric Cheng mac_srs_clear_flag(srs, SRS_RESTART_DONE);
2370da14cebeSEric Cheng
2371da14cebeSEric Cheng mac_srs_client_poll_restart(srs->srs_mcip, srs);
2372da14cebeSEric Cheng }
2373da14cebeSEric Cheng
2374da14cebeSEric Cheng /* Finally clear the flags to let the packets in */
2375da14cebeSEric Cheng mr = srs->srs_ring;
2376da14cebeSEric Cheng if (mr != NULL) {
2377da14cebeSEric Cheng MAC_RING_UNMARK(mr, MR_QUIESCE);
2378da14cebeSEric Cheng /* In case the ring was stopped, safely restart it */
23790dc2366fSVenugopal Iyer if (mr->mr_state != MR_INUSE)
2380da14cebeSEric Cheng (void) mac_start_ring(mr);
2381da14cebeSEric Cheng } else {
2382da14cebeSEric Cheng FLOW_UNMARK(flent, FE_QUIESCE);
2383da14cebeSEric Cheng }
2384da14cebeSEric Cheng }
2385da14cebeSEric Cheng
2386da14cebeSEric Cheng /*
2387da14cebeSEric Cheng * Temporary quiesce of a flow and associated Rx SRS.
2388da14cebeSEric Cheng * Please see block comment above mac_rx_classify_flow_rem.
2389da14cebeSEric Cheng */
2390da14cebeSEric Cheng /* ARGSUSED */
2391da14cebeSEric Cheng int
mac_rx_classify_flow_quiesce(flow_entry_t * flent,void * arg)2392da14cebeSEric Cheng mac_rx_classify_flow_quiesce(flow_entry_t *flent, void *arg)
2393da14cebeSEric Cheng {
2394da14cebeSEric Cheng int i;
2395da14cebeSEric Cheng
2396da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2397da14cebeSEric Cheng mac_rx_srs_quiesce((mac_soft_ring_set_t *)flent->fe_rx_srs[i],
2398da14cebeSEric Cheng SRS_QUIESCE);
2399da14cebeSEric Cheng }
2400da14cebeSEric Cheng return (0);
2401da14cebeSEric Cheng }
2402da14cebeSEric Cheng
2403da14cebeSEric Cheng /*
2404da14cebeSEric Cheng * Restart a flow and associated Rx SRS that has been quiesced temporarily
2405da14cebeSEric Cheng * Please see block comment above mac_rx_classify_flow_rem
2406da14cebeSEric Cheng */
2407da14cebeSEric Cheng /* ARGSUSED */
2408da14cebeSEric Cheng int
mac_rx_classify_flow_restart(flow_entry_t * flent,void * arg)2409da14cebeSEric Cheng mac_rx_classify_flow_restart(flow_entry_t *flent, void *arg)
2410da14cebeSEric Cheng {
2411da14cebeSEric Cheng int i;
2412da14cebeSEric Cheng
2413da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++)
2414da14cebeSEric Cheng mac_rx_srs_restart((mac_soft_ring_set_t *)flent->fe_rx_srs[i]);
2415da14cebeSEric Cheng
2416da14cebeSEric Cheng return (0);
2417da14cebeSEric Cheng }
2418da14cebeSEric Cheng
2419da14cebeSEric Cheng void
mac_srs_perm_quiesce(mac_client_handle_t mch,boolean_t on)2420da14cebeSEric Cheng mac_srs_perm_quiesce(mac_client_handle_t mch, boolean_t on)
2421da14cebeSEric Cheng {
2422da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2423da14cebeSEric Cheng flow_entry_t *flent = mcip->mci_flent;
2424da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
2425da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs;
2426da14cebeSEric Cheng int i;
2427da14cebeSEric Cheng
2428da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2429da14cebeSEric Cheng
2430da14cebeSEric Cheng if (flent == NULL)
2431da14cebeSEric Cheng return;
2432da14cebeSEric Cheng
2433da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2434da14cebeSEric Cheng mac_srs = flent->fe_rx_srs[i];
2435da14cebeSEric Cheng mutex_enter(&mac_srs->srs_lock);
2436da14cebeSEric Cheng if (on)
2437da14cebeSEric Cheng mac_srs->srs_state |= SRS_QUIESCE_PERM;
2438ba2e4443Sseb else
2439da14cebeSEric Cheng mac_srs->srs_state &= ~SRS_QUIESCE_PERM;
2440da14cebeSEric Cheng mutex_exit(&mac_srs->srs_lock);
24417c478bd9Sstevel@tonic-gate }
24427c478bd9Sstevel@tonic-gate }
24437c478bd9Sstevel@tonic-gate
24447c478bd9Sstevel@tonic-gate void
mac_rx_client_quiesce(mac_client_handle_t mch)2445da14cebeSEric Cheng mac_rx_client_quiesce(mac_client_handle_t mch)
24467c478bd9Sstevel@tonic-gate {
2447da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2448da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
24497c478bd9Sstevel@tonic-gate
2450da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2451da14cebeSEric Cheng
2452da14cebeSEric Cheng if (MCIP_DATAPATH_SETUP(mcip)) {
2453da14cebeSEric Cheng (void) mac_rx_classify_flow_quiesce(mcip->mci_flent,
2454da14cebeSEric Cheng NULL);
2455da14cebeSEric Cheng (void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2456da14cebeSEric Cheng mac_rx_classify_flow_quiesce, NULL);
24577c478bd9Sstevel@tonic-gate }
24587c478bd9Sstevel@tonic-gate }
24597c478bd9Sstevel@tonic-gate
24607c478bd9Sstevel@tonic-gate void
mac_rx_client_restart(mac_client_handle_t mch)2461da14cebeSEric Cheng mac_rx_client_restart(mac_client_handle_t mch)
24627c478bd9Sstevel@tonic-gate {
2463da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2464da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
24657c478bd9Sstevel@tonic-gate
2466da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2467da14cebeSEric Cheng
2468da14cebeSEric Cheng if (MCIP_DATAPATH_SETUP(mcip)) {
2469da14cebeSEric Cheng (void) mac_rx_classify_flow_restart(mcip->mci_flent, NULL);
2470da14cebeSEric Cheng (void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2471da14cebeSEric Cheng mac_rx_classify_flow_restart, NULL);
2472da14cebeSEric Cheng }
24737c478bd9Sstevel@tonic-gate }
24747c478bd9Sstevel@tonic-gate
24751f8aaf0dSethindra /*
2476da14cebeSEric Cheng * This function only quiesces the Tx SRS and softring worker threads. Callers
2477da14cebeSEric Cheng * need to make sure that there aren't any mac client threads doing current or
2478da14cebeSEric Cheng * future transmits in the mac before calling this function.
24797c478bd9Sstevel@tonic-gate */
24807c478bd9Sstevel@tonic-gate void
mac_tx_srs_quiesce(mac_soft_ring_set_t * srs,uint_t srs_quiesce_flag)2481da14cebeSEric Cheng mac_tx_srs_quiesce(mac_soft_ring_set_t *srs, uint_t srs_quiesce_flag)
24827c478bd9Sstevel@tonic-gate {
2483da14cebeSEric Cheng mac_client_impl_t *mcip = srs->srs_mcip;
2484da14cebeSEric Cheng
2485da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2486da14cebeSEric Cheng
2487da14cebeSEric Cheng ASSERT(srs->srs_type & SRST_TX);
2488da14cebeSEric Cheng ASSERT(srs_quiesce_flag == SRS_CONDEMNED ||
2489da14cebeSEric Cheng srs_quiesce_flag == SRS_QUIESCE);
24907c478bd9Sstevel@tonic-gate
24917c478bd9Sstevel@tonic-gate /*
2492da14cebeSEric Cheng * Signal the SRS to quiesce itself, and then cv_wait for the
2493da14cebeSEric Cheng * SRS quiesce to complete. The SRS worker thread will wake us
2494da14cebeSEric Cheng * up when the quiesce is complete
24957c478bd9Sstevel@tonic-gate */
2496da14cebeSEric Cheng mac_srs_signal(srs, srs_quiesce_flag);
2497da14cebeSEric Cheng mac_srs_quiesce_wait(srs, srs_quiesce_flag == SRS_QUIESCE ?
2498da14cebeSEric Cheng SRS_QUIESCE_DONE : SRS_CONDEMNED_DONE);
24997c478bd9Sstevel@tonic-gate }
25007c478bd9Sstevel@tonic-gate
2501da14cebeSEric Cheng void
mac_tx_srs_restart(mac_soft_ring_set_t * srs)2502da14cebeSEric Cheng mac_tx_srs_restart(mac_soft_ring_set_t *srs)
2503da14cebeSEric Cheng {
25041f8aaf0dSethindra /*
2505da14cebeSEric Cheng * Resizing the fanout could result in creation of new SRSs.
2506da14cebeSEric Cheng * They may not necessarily be in the quiesced state in which
2507da14cebeSEric Cheng * case it need be restarted
25081f8aaf0dSethindra */
2509da14cebeSEric Cheng if (!SRS_QUIESCED(srs))
25101f8aaf0dSethindra return;
25111f8aaf0dSethindra
2512da14cebeSEric Cheng mac_srs_signal(srs, SRS_RESTART);
2513da14cebeSEric Cheng mac_srs_quiesce_wait(srs, SRS_RESTART_DONE);
2514da14cebeSEric Cheng mac_srs_clear_flag(srs, SRS_RESTART_DONE);
25151f8aaf0dSethindra }
25161f8aaf0dSethindra
25171f8aaf0dSethindra /*
2518da14cebeSEric Cheng * Temporary quiesce of a flow and associated Rx SRS.
2519da14cebeSEric Cheng * Please see block comment above mac_rx_srs_quiesce
25201f8aaf0dSethindra */
2521da14cebeSEric Cheng /* ARGSUSED */
2522da14cebeSEric Cheng int
mac_tx_flow_quiesce(flow_entry_t * flent,void * arg)2523da14cebeSEric Cheng mac_tx_flow_quiesce(flow_entry_t *flent, void *arg)
25241f8aaf0dSethindra {
2525da14cebeSEric Cheng /*
2526da14cebeSEric Cheng * The fe_tx_srs is null for a subflow on an interface that is
2527da14cebeSEric Cheng * not plumbed
2528da14cebeSEric Cheng */
2529da14cebeSEric Cheng if (flent->fe_tx_srs != NULL)
2530da14cebeSEric Cheng mac_tx_srs_quiesce(flent->fe_tx_srs, SRS_QUIESCE);
2531da14cebeSEric Cheng return (0);
25327c478bd9Sstevel@tonic-gate }
25337c478bd9Sstevel@tonic-gate
2534da14cebeSEric Cheng /* ARGSUSED */
2535da14cebeSEric Cheng int
mac_tx_flow_restart(flow_entry_t * flent,void * arg)2536da14cebeSEric Cheng mac_tx_flow_restart(flow_entry_t *flent, void *arg)
25377c478bd9Sstevel@tonic-gate {
25387c478bd9Sstevel@tonic-gate /*
2539da14cebeSEric Cheng * The fe_tx_srs is null for a subflow on an interface that is
2540da14cebeSEric Cheng * not plumbed
25417c478bd9Sstevel@tonic-gate */
2542da14cebeSEric Cheng if (flent->fe_tx_srs != NULL)
2543da14cebeSEric Cheng mac_tx_srs_restart(flent->fe_tx_srs);
2544da14cebeSEric Cheng return (0);
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate
25470dc2366fSVenugopal Iyer static void
i_mac_tx_client_quiesce(mac_client_handle_t mch,uint_t srs_quiesce_flag)25480dc2366fSVenugopal Iyer i_mac_tx_client_quiesce(mac_client_handle_t mch, uint_t srs_quiesce_flag)
25497c478bd9Sstevel@tonic-gate {
25500dc2366fSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
25510dc2366fSVenugopal Iyer
2552da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
25537c478bd9Sstevel@tonic-gate
2554da14cebeSEric Cheng mac_tx_client_block(mcip);
2555da14cebeSEric Cheng if (MCIP_TX_SRS(mcip) != NULL) {
2556da14cebeSEric Cheng mac_tx_srs_quiesce(MCIP_TX_SRS(mcip), srs_quiesce_flag);
2557da14cebeSEric Cheng (void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2558da14cebeSEric Cheng mac_tx_flow_quiesce, NULL);
25597c478bd9Sstevel@tonic-gate }
2560ba2e4443Sseb }
2561ba2e4443Sseb
2562ba2e4443Sseb void
mac_tx_client_quiesce(mac_client_handle_t mch)25630dc2366fSVenugopal Iyer mac_tx_client_quiesce(mac_client_handle_t mch)
2564ba2e4443Sseb {
25650dc2366fSVenugopal Iyer i_mac_tx_client_quiesce(mch, SRS_QUIESCE);
25660dc2366fSVenugopal Iyer }
25670dc2366fSVenugopal Iyer
25680dc2366fSVenugopal Iyer void
mac_tx_client_condemn(mac_client_handle_t mch)25690dc2366fSVenugopal Iyer mac_tx_client_condemn(mac_client_handle_t mch)
25700dc2366fSVenugopal Iyer {
25710dc2366fSVenugopal Iyer i_mac_tx_client_quiesce(mch, SRS_CONDEMNED);
25720dc2366fSVenugopal Iyer }
25730dc2366fSVenugopal Iyer
25740dc2366fSVenugopal Iyer void
mac_tx_client_restart(mac_client_handle_t mch)25750dc2366fSVenugopal Iyer mac_tx_client_restart(mac_client_handle_t mch)
25760dc2366fSVenugopal Iyer {
25770dc2366fSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
25780dc2366fSVenugopal Iyer
2579da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2580da14cebeSEric Cheng
2581da14cebeSEric Cheng mac_tx_client_unblock(mcip);
2582da14cebeSEric Cheng if (MCIP_TX_SRS(mcip) != NULL) {
2583da14cebeSEric Cheng mac_tx_srs_restart(MCIP_TX_SRS(mcip));
2584da14cebeSEric Cheng (void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2585da14cebeSEric Cheng mac_tx_flow_restart, NULL);
2586da14cebeSEric Cheng }
2587da14cebeSEric Cheng }
2588da14cebeSEric Cheng
2589da14cebeSEric Cheng void
mac_tx_client_flush(mac_client_impl_t * mcip)2590da14cebeSEric Cheng mac_tx_client_flush(mac_client_impl_t *mcip)
2591da14cebeSEric Cheng {
2592da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2593da14cebeSEric Cheng
25940dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
25950dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
2596da14cebeSEric Cheng }
2597da14cebeSEric Cheng
2598da14cebeSEric Cheng void
mac_client_quiesce(mac_client_impl_t * mcip)2599da14cebeSEric Cheng mac_client_quiesce(mac_client_impl_t *mcip)
2600da14cebeSEric Cheng {
2601da14cebeSEric Cheng mac_rx_client_quiesce((mac_client_handle_t)mcip);
26020dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
2603da14cebeSEric Cheng }
2604da14cebeSEric Cheng
2605da14cebeSEric Cheng void
mac_client_restart(mac_client_impl_t * mcip)2606da14cebeSEric Cheng mac_client_restart(mac_client_impl_t *mcip)
2607da14cebeSEric Cheng {
2608da14cebeSEric Cheng mac_rx_client_restart((mac_client_handle_t)mcip);
26090dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
2610210db224Sericheng }
26117c478bd9Sstevel@tonic-gate
26127c478bd9Sstevel@tonic-gate /*
2613d62bc4baSyz147064 * Allocate a minor number.
2614d62bc4baSyz147064 */
2615d62bc4baSyz147064 minor_t
mac_minor_hold(boolean_t sleep)2616d62bc4baSyz147064 mac_minor_hold(boolean_t sleep)
2617d62bc4baSyz147064 {
2618249622b3SJohn Levon id_t id;
2619d62bc4baSyz147064
2620d62bc4baSyz147064 /*
2621d62bc4baSyz147064 * Grab a value from the arena.
2622d62bc4baSyz147064 */
26231a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&minor_count);
2624d62bc4baSyz147064
2625d62bc4baSyz147064 if (sleep)
2626249622b3SJohn Levon return ((uint_t)id_alloc(minor_ids));
2627d62bc4baSyz147064
2628249622b3SJohn Levon if ((id = id_alloc_nosleep(minor_ids)) == -1) {
26291a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&minor_count);
2630d62bc4baSyz147064 return (0);
2631d62bc4baSyz147064 }
2632d62bc4baSyz147064
2633249622b3SJohn Levon return ((uint_t)id);
2634d62bc4baSyz147064 }
2635d62bc4baSyz147064
2636d62bc4baSyz147064 /*
2637d62bc4baSyz147064 * Release a previously allocated minor number.
2638d62bc4baSyz147064 */
2639d62bc4baSyz147064 void
mac_minor_rele(minor_t minor)2640d62bc4baSyz147064 mac_minor_rele(minor_t minor)
2641d62bc4baSyz147064 {
2642d62bc4baSyz147064 /*
2643d62bc4baSyz147064 * Return the value to the arena.
2644d62bc4baSyz147064 */
2645d62bc4baSyz147064 id_free(minor_ids, minor);
26461a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&minor_count);
2647d62bc4baSyz147064 }
2648d62bc4baSyz147064
2649d62bc4baSyz147064 uint32_t
mac_no_notification(mac_handle_t mh)2650d62bc4baSyz147064 mac_no_notification(mac_handle_t mh)
2651d62bc4baSyz147064 {
2652d62bc4baSyz147064 mac_impl_t *mip = (mac_impl_t *)mh;
26535d460eafSCathy Zhou
26545d460eafSCathy Zhou return (((mip->mi_state_flags & MIS_LEGACY) != 0) ?
26555d460eafSCathy Zhou mip->mi_capab_legacy.ml_unsup_note : 0);
2656d62bc4baSyz147064 }
2657d62bc4baSyz147064
2658d62bc4baSyz147064 /*
2659da14cebeSEric Cheng * Prevent any new opens of this mac in preparation for unregister
26607c478bd9Sstevel@tonic-gate */
2661ba2e4443Sseb int
i_mac_disable(mac_impl_t * mip)2662da14cebeSEric Cheng i_mac_disable(mac_impl_t *mip)
2663ba2e4443Sseb {
2664da14cebeSEric Cheng mac_client_impl_t *mcip;
26657c478bd9Sstevel@tonic-gate
2666fbe1721bSyz147064 rw_enter(&i_mac_impl_lock, RW_WRITER);
2667da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED) {
2668da14cebeSEric Cheng /* Already disabled, return success */
2669fbe1721bSyz147064 rw_exit(&i_mac_impl_lock);
2670da14cebeSEric Cheng return (0);
2671fbe1721bSyz147064 }
2672da14cebeSEric Cheng /*
2673da14cebeSEric Cheng * See if there are any other references to this mac_t (e.g., VLAN's).
2674da14cebeSEric Cheng * If so return failure. If all the other checks below pass, then
2675da14cebeSEric Cheng * set mi_disabled atomically under the i_mac_impl_lock to prevent
2676da14cebeSEric Cheng * any new VLAN's from being created or new mac client opens of this
2677da14cebeSEric Cheng * mac end point.
2678da14cebeSEric Cheng */
2679da14cebeSEric Cheng if (mip->mi_ref > 0) {
2680da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
2681da14cebeSEric Cheng return (EBUSY);
2682da14cebeSEric Cheng }
2683e7801d59Ssowmini
2684490ed22dSyz147064 /*
2685da14cebeSEric Cheng * mac clients must delete all multicast groups they join before
2686da14cebeSEric Cheng * closing. bcast groups are reference counted, the last client
2687da14cebeSEric Cheng * to delete the group will wait till the group is physically
2688da14cebeSEric Cheng * deleted. Since all clients have closed this mac end point
2689da14cebeSEric Cheng * mi_bcast_ngrps must be zero at this point
2690490ed22dSyz147064 */
2691da14cebeSEric Cheng ASSERT(mip->mi_bcast_ngrps == 0);
2692490ed22dSyz147064
2693da14cebeSEric Cheng /*
2694da14cebeSEric Cheng * Don't let go of this if it has some flows.
2695da14cebeSEric Cheng * All other code guarantees no flows are added to a disabled
2696da14cebeSEric Cheng * mac, therefore it is sufficient to check for the flow table
2697da14cebeSEric Cheng * only here.
2698da14cebeSEric Cheng */
2699da14cebeSEric Cheng mcip = mac_primary_client_handle(mip);
2700da14cebeSEric Cheng if ((mcip != NULL) && mac_link_has_flows((mac_client_handle_t)mcip)) {
2701ba2e4443Sseb rw_exit(&i_mac_impl_lock);
2702da14cebeSEric Cheng return (ENOTEMPTY);
2703da14cebeSEric Cheng }
2704fbe1721bSyz147064
2705da14cebeSEric Cheng mip->mi_state_flags |= MIS_DISABLED;
2706da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
27077c478bd9Sstevel@tonic-gate return (0);
27080487e2c9Sgd78059 }
27090487e2c9Sgd78059
2710da14cebeSEric Cheng int
mac_disable_nowait(mac_handle_t mh)2711da14cebeSEric Cheng mac_disable_nowait(mac_handle_t mh)
2712da14cebeSEric Cheng {
2713da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
2714da14cebeSEric Cheng int err;
2715ba2e4443Sseb
2716da14cebeSEric Cheng if ((err = i_mac_perim_enter_nowait(mip)) != 0)
2717da14cebeSEric Cheng return (err);
2718da14cebeSEric Cheng err = i_mac_disable(mip);
2719da14cebeSEric Cheng i_mac_perim_exit(mip);
2720210db224Sericheng return (err);
27217c478bd9Sstevel@tonic-gate }
27227c478bd9Sstevel@tonic-gate
27237c478bd9Sstevel@tonic-gate int
mac_disable(mac_handle_t mh)2724843e1988Sjohnlev mac_disable(mac_handle_t mh)
27257c478bd9Sstevel@tonic-gate {
2726ba2e4443Sseb mac_impl_t *mip = (mac_impl_t *)mh;
2727843e1988Sjohnlev int err;
2728da14cebeSEric Cheng
2729da14cebeSEric Cheng i_mac_perim_enter(mip);
2730da14cebeSEric Cheng err = i_mac_disable(mip);
2731da14cebeSEric Cheng i_mac_perim_exit(mip);
2732843e1988Sjohnlev
2733843e1988Sjohnlev /*
2734da14cebeSEric Cheng * Clean up notification thread and wait for it to exit.
2735843e1988Sjohnlev */
2736da14cebeSEric Cheng if (err == 0)
2737da14cebeSEric Cheng i_mac_notify_exit(mip);
2738da14cebeSEric Cheng
2739843e1988Sjohnlev return (err);
2740843e1988Sjohnlev }
2741843e1988Sjohnlev
27427c478bd9Sstevel@tonic-gate /*
2743da14cebeSEric Cheng * Called when the MAC instance has a non empty flow table, to de-multiplex
2744da14cebeSEric Cheng * incoming packets to the right flow.
27450487e2c9Sgd78059 */
2746da14cebeSEric Cheng /* ARGSUSED */
2747*67cac09cSKyle Simpson static flow_entry_t *
mac_rx_classify(mac_impl_t * mip,mac_resource_handle_t mrh,mblk_t * mp)2748da14cebeSEric Cheng mac_rx_classify(mac_impl_t *mip, mac_resource_handle_t mrh, mblk_t *mp)
2749da14cebeSEric Cheng {
2750da14cebeSEric Cheng flow_entry_t *flent = NULL;
2751da14cebeSEric Cheng uint_t flags = FLOW_INBOUND;
2752da14cebeSEric Cheng int err;
2753ba2e4443Sseb
2754da14cebeSEric Cheng err = mac_flow_lookup(mip->mi_flow_tab, mp, flags, &flent);
2755*67cac09cSKyle Simpson if (err == 0) {
2756da14cebeSEric Cheng mac_client_impl_t *mcip;
27571f8aaf0dSethindra
27581f8aaf0dSethindra /*
2759da14cebeSEric Cheng * This flent might just be an additional one on the MAC client,
2760da14cebeSEric Cheng * i.e. for classification purposes (different fdesc), however
2761da14cebeSEric Cheng * the resources, SRS et. al., are in the mci_flent, so if
2762da14cebeSEric Cheng * this isn't the mci_flent, we need to get it.
27631f8aaf0dSethindra */
2764da14cebeSEric Cheng if ((mcip = flent->fe_mcip) != NULL &&
2765da14cebeSEric Cheng mcip->mci_flent != flent) {
2766da14cebeSEric Cheng FLOW_REFRELE(flent);
2767da14cebeSEric Cheng flent = mcip->mci_flent;
2768da14cebeSEric Cheng FLOW_TRY_REFHOLD(flent, err);
2769da14cebeSEric Cheng if (err != 0)
2770843e1988Sjohnlev return (NULL);
2771843e1988Sjohnlev }
2772*67cac09cSKyle Simpson }
2773*67cac09cSKyle Simpson
2774*67cac09cSKyle Simpson /* flent will be NULL if mac_flow_lookup fails to find a match. */
2775*67cac09cSKyle Simpson return (flent);
2776*67cac09cSKyle Simpson }
2777843e1988Sjohnlev
27787c478bd9Sstevel@tonic-gate mblk_t *
mac_rx_flow(mac_handle_t mh,mac_resource_handle_t mrh,mblk_t * mp_chain)2779da14cebeSEric Cheng mac_rx_flow(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
27807c478bd9Sstevel@tonic-gate {
2781da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
2782*67cac09cSKyle Simpson mblk_t *mp_next, *tail, **unclass_nextp;
2783*67cac09cSKyle Simpson mblk_t *unclass_list = NULL;
2784*67cac09cSKyle Simpson flow_entry_t *prev_flent = NULL;
27857c478bd9Sstevel@tonic-gate
2786843e1988Sjohnlev /*
2787da14cebeSEric Cheng * We walk the chain and attempt to classify each packet.
2788da14cebeSEric Cheng * The packets that couldn't be classified will be returned
2789da14cebeSEric Cheng * back to the caller.
2790*67cac09cSKyle Simpson *
2791*67cac09cSKyle Simpson * We want to batch together runs of matched packets bound
2792*67cac09cSKyle Simpson * for the same flent into the same callback. Unmatched
2793*67cac09cSKyle Simpson * packets should not break an ongoing chain.
2794843e1988Sjohnlev */
2795*67cac09cSKyle Simpson mp_next = tail = mp_chain;
2796*67cac09cSKyle Simpson unclass_nextp = &unclass_list;
2797*67cac09cSKyle Simpson while (mp_next != NULL) {
2798*67cac09cSKyle Simpson flow_entry_t *flent;
2799*67cac09cSKyle Simpson mblk_t *mp = mp_next;
2800*67cac09cSKyle Simpson mp_next = mp_next->b_next;
2801*67cac09cSKyle Simpson mp->b_next = NULL;
28027c478bd9Sstevel@tonic-gate
2803*67cac09cSKyle Simpson flent = mac_rx_classify(mip, mrh, mp);
2804*67cac09cSKyle Simpson if (flent == NULL) {
2805*67cac09cSKyle Simpson /*
2806*67cac09cSKyle Simpson * Add the current mblk_t to the end of the
2807*67cac09cSKyle Simpson * unclassified packet chain at 'unclass_list'.
2808*67cac09cSKyle Simpson * Move the current head forward if we have not
2809*67cac09cSKyle Simpson * yet made any match.
2810*67cac09cSKyle Simpson */
2811*67cac09cSKyle Simpson if (prev_flent == NULL) {
2812*67cac09cSKyle Simpson mp_chain = mp_next;
2813*67cac09cSKyle Simpson tail = mp_next;
2814da14cebeSEric Cheng }
2815*67cac09cSKyle Simpson *unclass_nextp = mp;
2816*67cac09cSKyle Simpson unclass_nextp = &mp->b_next;
2817*67cac09cSKyle Simpson continue;
2818da14cebeSEric Cheng }
2819*67cac09cSKyle Simpson
2820*67cac09cSKyle Simpson if (prev_flent == NULL || flent == prev_flent) {
2821*67cac09cSKyle Simpson /* Either the first valid match, or in the same chain */
2822*67cac09cSKyle Simpson if (prev_flent != NULL)
2823*67cac09cSKyle Simpson FLOW_REFRELE(prev_flent);
2824*67cac09cSKyle Simpson if (mp != tail)
2825*67cac09cSKyle Simpson tail->b_next = mp;
2826*67cac09cSKyle Simpson } else {
2827*67cac09cSKyle Simpson ASSERT3P(prev_flent, !=, NULL);
2828*67cac09cSKyle Simpson (prev_flent->fe_cb_fn)(prev_flent->fe_cb_arg1,
2829*67cac09cSKyle Simpson prev_flent->fe_cb_arg2, mp_chain, B_FALSE);
2830*67cac09cSKyle Simpson FLOW_REFRELE(prev_flent);
2831*67cac09cSKyle Simpson mp_chain = mp;
2832*67cac09cSKyle Simpson }
2833*67cac09cSKyle Simpson
2834*67cac09cSKyle Simpson prev_flent = flent;
2835*67cac09cSKyle Simpson tail = mp;
2836*67cac09cSKyle Simpson }
2837*67cac09cSKyle Simpson /* Last chain */
2838*67cac09cSKyle Simpson if (mp_chain != NULL) {
2839*67cac09cSKyle Simpson ASSERT3P(prev_flent, !=, NULL);
2840*67cac09cSKyle Simpson (prev_flent->fe_cb_fn)(prev_flent->fe_cb_arg1,
2841*67cac09cSKyle Simpson prev_flent->fe_cb_arg2, mp_chain, B_FALSE);
2842*67cac09cSKyle Simpson FLOW_REFRELE(prev_flent);
2843*67cac09cSKyle Simpson }
2844*67cac09cSKyle Simpson return (unclass_list);
28457c478bd9Sstevel@tonic-gate }
28467c478bd9Sstevel@tonic-gate
2847da14cebeSEric Cheng static int
mac_tx_flow_srs_wakeup(flow_entry_t * flent,void * arg)2848da14cebeSEric Cheng mac_tx_flow_srs_wakeup(flow_entry_t *flent, void *arg)
2849843e1988Sjohnlev {
2850da14cebeSEric Cheng mac_ring_handle_t ring = arg;
2851843e1988Sjohnlev
2852da14cebeSEric Cheng if (flent->fe_tx_srs)
2853da14cebeSEric Cheng mac_tx_srs_wakeup(flent->fe_tx_srs, ring);
2854ba2e4443Sseb return (0);
2855ba2e4443Sseb }
2856ba2e4443Sseb
28577c478bd9Sstevel@tonic-gate void
i_mac_tx_srs_notify(mac_impl_t * mip,mac_ring_handle_t ring)2858da14cebeSEric Cheng i_mac_tx_srs_notify(mac_impl_t *mip, mac_ring_handle_t ring)
2859da14cebeSEric Cheng {
2860da14cebeSEric Cheng mac_client_impl_t *cclient;
2861da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs;
2862da14cebeSEric Cheng
2863da14cebeSEric Cheng /*
2864da14cebeSEric Cheng * After grabbing the mi_rw_lock, the list of clients can't change.
2865da14cebeSEric Cheng * If there are any clients mi_disabled must be B_FALSE and can't
2866da14cebeSEric Cheng * get set since there are clients. If there aren't any clients we
2867da14cebeSEric Cheng * don't do anything. In any case the mip has to be valid. The driver
2868da14cebeSEric Cheng * must make sure that it goes single threaded (with respect to mac
2869da14cebeSEric Cheng * calls) and wait for all pending mac calls to finish before calling
2870da14cebeSEric Cheng * mac_unregister.
2871da14cebeSEric Cheng */
2872da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_READER);
2873da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED) {
2874da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
2875da14cebeSEric Cheng return;
2876da14cebeSEric Cheng }
2877da14cebeSEric Cheng
2878da14cebeSEric Cheng /*
2879da14cebeSEric Cheng * Get MAC tx srs from walking mac_client_handle list.
2880da14cebeSEric Cheng */
2881da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER);
2882da14cebeSEric Cheng for (cclient = mip->mi_clients_list; cclient != NULL;
2883da14cebeSEric Cheng cclient = cclient->mci_client_next) {
28840dc2366fSVenugopal Iyer if ((mac_srs = MCIP_TX_SRS(cclient)) != NULL) {
2885da14cebeSEric Cheng mac_tx_srs_wakeup(mac_srs, ring);
28860dc2366fSVenugopal Iyer } else {
28870dc2366fSVenugopal Iyer /*
28880dc2366fSVenugopal Iyer * Aggr opens underlying ports in exclusive mode
28890dc2366fSVenugopal Iyer * and registers flow control callbacks using
28900dc2366fSVenugopal Iyer * mac_tx_client_notify(). When opened in
28910dc2366fSVenugopal Iyer * exclusive mode, Tx SRS won't be created
28920dc2366fSVenugopal Iyer * during mac_unicast_add().
28930dc2366fSVenugopal Iyer */
28940dc2366fSVenugopal Iyer if (cclient->mci_state_flags & MCIS_EXCLUSIVE) {
28950dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(cclient,
28960dc2366fSVenugopal Iyer (mac_tx_cookie_t)ring);
28970dc2366fSVenugopal Iyer }
28980dc2366fSVenugopal Iyer }
2899ae6aa22aSVenugopal Iyer (void) mac_flow_walk(cclient->mci_subflow_tab,
2900da14cebeSEric Cheng mac_tx_flow_srs_wakeup, ring);
2901da14cebeSEric Cheng }
2902da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock);
2903da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
2904da14cebeSEric Cheng }
2905da14cebeSEric Cheng
2906da14cebeSEric Cheng /* ARGSUSED */
2907da14cebeSEric Cheng void
mac_multicast_refresh(mac_handle_t mh,mac_multicst_t refresh,void * arg,boolean_t add)2908da14cebeSEric Cheng mac_multicast_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
29097c478bd9Sstevel@tonic-gate boolean_t add)
29107c478bd9Sstevel@tonic-gate {
2911ba2e4443Sseb mac_impl_t *mip = (mac_impl_t *)mh;
29127c478bd9Sstevel@tonic-gate
2913da14cebeSEric Cheng i_mac_perim_enter((mac_impl_t *)mh);
29147c478bd9Sstevel@tonic-gate /*
29157c478bd9Sstevel@tonic-gate * If no specific refresh function was given then default to the
29167c478bd9Sstevel@tonic-gate * driver's m_multicst entry point.
29177c478bd9Sstevel@tonic-gate */
29187c478bd9Sstevel@tonic-gate if (refresh == NULL) {
2919ba2e4443Sseb refresh = mip->mi_multicst;
2920ba2e4443Sseb arg = mip->mi_driver;
29217c478bd9Sstevel@tonic-gate }
29227c478bd9Sstevel@tonic-gate
2923da14cebeSEric Cheng mac_bcast_refresh(mip, refresh, arg, add);
2924da14cebeSEric Cheng i_mac_perim_exit((mac_impl_t *)mh);
29257c478bd9Sstevel@tonic-gate }
29267c478bd9Sstevel@tonic-gate
29277c478bd9Sstevel@tonic-gate void
mac_promisc_refresh(mac_handle_t mh,mac_setpromisc_t refresh,void * arg)2928ba2e4443Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
29297c478bd9Sstevel@tonic-gate {
2930ba2e4443Sseb mac_impl_t *mip = (mac_impl_t *)mh;
29317c478bd9Sstevel@tonic-gate
29327c478bd9Sstevel@tonic-gate /*
29337c478bd9Sstevel@tonic-gate * If no specific refresh function was given then default to the
29347c478bd9Sstevel@tonic-gate * driver's m_promisc entry point.
29357c478bd9Sstevel@tonic-gate */
29367c478bd9Sstevel@tonic-gate if (refresh == NULL) {
2937ba2e4443Sseb refresh = mip->mi_setpromisc;
2938ba2e4443Sseb arg = mip->mi_driver;
29397c478bd9Sstevel@tonic-gate }
29407c478bd9Sstevel@tonic-gate ASSERT(refresh != NULL);
29417c478bd9Sstevel@tonic-gate
29427c478bd9Sstevel@tonic-gate /*
29437c478bd9Sstevel@tonic-gate * Call the refresh function with the current promiscuity.
29447c478bd9Sstevel@tonic-gate */
29457c478bd9Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0));
29467c478bd9Sstevel@tonic-gate }
29477c478bd9Sstevel@tonic-gate
2948d62bc4baSyz147064 /*
2949d62bc4baSyz147064 * The mac client requests that the mac not to change its margin size to
2950d62bc4baSyz147064 * be less than the specified value. If "current" is B_TRUE, then the client
2951d62bc4baSyz147064 * requests the mac not to change its margin size to be smaller than the
2952d62bc4baSyz147064 * current size. Further, return the current margin size value in this case.
2953d62bc4baSyz147064 *
2954d62bc4baSyz147064 * We keep every requested size in an ordered list from largest to smallest.
2955d62bc4baSyz147064 */
2956d62bc4baSyz147064 int
mac_margin_add(mac_handle_t mh,uint32_t * marginp,boolean_t current)2957d62bc4baSyz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
2958d62bc4baSyz147064 {
2959d62bc4baSyz147064 mac_impl_t *mip = (mac_impl_t *)mh;
2960d62bc4baSyz147064 mac_margin_req_t **pp, *p;
2961d62bc4baSyz147064 int err = 0;
2962d62bc4baSyz147064
2963da14cebeSEric Cheng rw_enter(&(mip->mi_rw_lock), RW_WRITER);
2964d62bc4baSyz147064 if (current)
2965d62bc4baSyz147064 *marginp = mip->mi_margin;
2966d62bc4baSyz147064
2967d62bc4baSyz147064 /*
2968d62bc4baSyz147064 * If the current margin value cannot satisfy the margin requested,
2969d62bc4baSyz147064 * return ENOTSUP directly.
2970d62bc4baSyz147064 */
2971d62bc4baSyz147064 if (*marginp > mip->mi_margin) {
2972d62bc4baSyz147064 err = ENOTSUP;
2973d62bc4baSyz147064 goto done;
2974d62bc4baSyz147064 }
2975d62bc4baSyz147064
2976d62bc4baSyz147064 /*
2977d62bc4baSyz147064 * Check whether the given margin is already in the list. If so,
2978d62bc4baSyz147064 * bump the reference count.
2979d62bc4baSyz147064 */
2980da14cebeSEric Cheng for (pp = &mip->mi_mmrp; (p = *pp) != NULL; pp = &p->mmr_nextp) {
2981d62bc4baSyz147064 if (p->mmr_margin == *marginp) {
2982d62bc4baSyz147064 /*
2983d62bc4baSyz147064 * The margin requested is already in the list,
2984d62bc4baSyz147064 * so just bump the reference count.
2985d62bc4baSyz147064 */
2986d62bc4baSyz147064 p->mmr_ref++;
2987d62bc4baSyz147064 goto done;
2988d62bc4baSyz147064 }
2989d62bc4baSyz147064 if (p->mmr_margin < *marginp)
2990d62bc4baSyz147064 break;
2991d62bc4baSyz147064 }
2992d62bc4baSyz147064
2993d62bc4baSyz147064
2994da14cebeSEric Cheng p = kmem_zalloc(sizeof (mac_margin_req_t), KM_SLEEP);
2995d62bc4baSyz147064 p->mmr_margin = *marginp;
2996d62bc4baSyz147064 p->mmr_ref++;
2997d62bc4baSyz147064 p->mmr_nextp = *pp;
2998d62bc4baSyz147064 *pp = p;
2999d62bc4baSyz147064
3000d62bc4baSyz147064 done:
3001da14cebeSEric Cheng rw_exit(&(mip->mi_rw_lock));
3002d62bc4baSyz147064 return (err);
3003d62bc4baSyz147064 }
3004d62bc4baSyz147064
3005d62bc4baSyz147064 /*
3006d62bc4baSyz147064 * The mac client requests to cancel its previous mac_margin_add() request.
3007d62bc4baSyz147064 * We remove the requested margin size from the list.
3008d62bc4baSyz147064 */
3009d62bc4baSyz147064 int
mac_margin_remove(mac_handle_t mh,uint32_t margin)3010d62bc4baSyz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin)
3011d62bc4baSyz147064 {
3012d62bc4baSyz147064 mac_impl_t *mip = (mac_impl_t *)mh;
3013d62bc4baSyz147064 mac_margin_req_t **pp, *p;
3014d62bc4baSyz147064 int err = 0;
3015d62bc4baSyz147064
3016da14cebeSEric Cheng rw_enter(&(mip->mi_rw_lock), RW_WRITER);
3017d62bc4baSyz147064 /*
3018d62bc4baSyz147064 * Find the entry in the list for the given margin.
3019d62bc4baSyz147064 */
3020d62bc4baSyz147064 for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
3021d62bc4baSyz147064 if (p->mmr_margin == margin) {
3022d62bc4baSyz147064 if (--p->mmr_ref == 0)
3023d62bc4baSyz147064 break;
3024d62bc4baSyz147064
3025d62bc4baSyz147064 /*
3026d62bc4baSyz147064 * There is still a reference to this address so
3027d62bc4baSyz147064 * there's nothing more to do.
3028d62bc4baSyz147064 */
3029d62bc4baSyz147064 goto done;
3030d62bc4baSyz147064 }
3031d62bc4baSyz147064 }
3032d62bc4baSyz147064
3033d62bc4baSyz147064 /*
3034d62bc4baSyz147064 * We did not find an entry for the given margin.
3035d62bc4baSyz147064 */
3036d62bc4baSyz147064 if (p == NULL) {
3037d62bc4baSyz147064 err = ENOENT;
3038d62bc4baSyz147064 goto done;
3039d62bc4baSyz147064 }
3040d62bc4baSyz147064
3041d62bc4baSyz147064 ASSERT(p->mmr_ref == 0);
3042d62bc4baSyz147064
3043d62bc4baSyz147064 /*
3044d62bc4baSyz147064 * Remove it from the list.
3045d62bc4baSyz147064 */
3046d62bc4baSyz147064 *pp = p->mmr_nextp;
3047d62bc4baSyz147064 kmem_free(p, sizeof (mac_margin_req_t));
3048d62bc4baSyz147064 done:
3049da14cebeSEric Cheng rw_exit(&(mip->mi_rw_lock));
3050d62bc4baSyz147064 return (err);
3051d62bc4baSyz147064 }
3052d62bc4baSyz147064
3053d62bc4baSyz147064 boolean_t
mac_margin_update(mac_handle_t mh,uint32_t margin)3054d62bc4baSyz147064 mac_margin_update(mac_handle_t mh, uint32_t margin)
3055d62bc4baSyz147064 {
3056d62bc4baSyz147064 mac_impl_t *mip = (mac_impl_t *)mh;
3057d62bc4baSyz147064 uint32_t margin_needed = 0;
3058d62bc4baSyz147064
3059da14cebeSEric Cheng rw_enter(&(mip->mi_rw_lock), RW_WRITER);
3060d62bc4baSyz147064
3061d62bc4baSyz147064 if (mip->mi_mmrp != NULL)
3062d62bc4baSyz147064 margin_needed = mip->mi_mmrp->mmr_margin;
3063d62bc4baSyz147064
3064d62bc4baSyz147064 if (margin_needed <= margin)
3065d62bc4baSyz147064 mip->mi_margin = margin;
3066d62bc4baSyz147064
3067da14cebeSEric Cheng rw_exit(&(mip->mi_rw_lock));
3068d62bc4baSyz147064
3069d62bc4baSyz147064 if (margin_needed <= margin)
3070d62bc4baSyz147064 i_mac_notify(mip, MAC_NOTE_MARGIN);
3071d62bc4baSyz147064
3072d62bc4baSyz147064 return (margin_needed <= margin);
3073d62bc4baSyz147064 }
3074d62bc4baSyz147064
3075ba2e4443Sseb /*
3076a776d98eSRobert Mustacchi * MAC clients use this interface to request that a MAC device not change its
3077a776d98eSRobert Mustacchi * MTU below the specified amount. At this time, that amount must be within the
3078a776d98eSRobert Mustacchi * range of the device's current minimum and the device's current maximum. eg. a
3079a776d98eSRobert Mustacchi * client cannot request a 3000 byte MTU when the device's MTU is currently
3080a776d98eSRobert Mustacchi * 2000.
3081a776d98eSRobert Mustacchi *
3082a776d98eSRobert Mustacchi * If "current" is set to B_TRUE, then the request is to simply to reserve the
3083a776d98eSRobert Mustacchi * current underlying mac's maximum for this mac client and return it in mtup.
3084a776d98eSRobert Mustacchi */
3085a776d98eSRobert Mustacchi int
mac_mtu_add(mac_handle_t mh,uint32_t * mtup,boolean_t current)3086a776d98eSRobert Mustacchi mac_mtu_add(mac_handle_t mh, uint32_t *mtup, boolean_t current)
3087a776d98eSRobert Mustacchi {
3088a776d98eSRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
3089a776d98eSRobert Mustacchi mac_mtu_req_t *prev, *cur;
3090a776d98eSRobert Mustacchi mac_propval_range_t mpr;
3091a776d98eSRobert Mustacchi int err;
3092a776d98eSRobert Mustacchi
3093a776d98eSRobert Mustacchi i_mac_perim_enter(mip);
3094a776d98eSRobert Mustacchi rw_enter(&mip->mi_rw_lock, RW_WRITER);
3095a776d98eSRobert Mustacchi
3096a776d98eSRobert Mustacchi if (current == B_TRUE)
3097a776d98eSRobert Mustacchi *mtup = mip->mi_sdu_max;
3098a776d98eSRobert Mustacchi mpr.mpr_count = 1;
3099a776d98eSRobert Mustacchi err = mac_prop_info(mh, MAC_PROP_MTU, "mtu", NULL, 0, &mpr, NULL);
3100a776d98eSRobert Mustacchi if (err != 0) {
3101a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3102a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3103a776d98eSRobert Mustacchi return (err);
3104a776d98eSRobert Mustacchi }
3105a776d98eSRobert Mustacchi
3106a776d98eSRobert Mustacchi if (*mtup > mip->mi_sdu_max ||
3107a776d98eSRobert Mustacchi *mtup < mpr.mpr_range_uint32[0].mpur_min) {
3108a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3109a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3110a776d98eSRobert Mustacchi return (ENOTSUP);
3111a776d98eSRobert Mustacchi }
3112a776d98eSRobert Mustacchi
3113a776d98eSRobert Mustacchi prev = NULL;
3114a776d98eSRobert Mustacchi for (cur = mip->mi_mtrp; cur != NULL; cur = cur->mtr_nextp) {
3115a776d98eSRobert Mustacchi if (*mtup == cur->mtr_mtu) {
3116a776d98eSRobert Mustacchi cur->mtr_ref++;
3117a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3118a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3119a776d98eSRobert Mustacchi return (0);
3120a776d98eSRobert Mustacchi }
3121a776d98eSRobert Mustacchi
3122a776d98eSRobert Mustacchi if (*mtup > cur->mtr_mtu)
3123a776d98eSRobert Mustacchi break;
3124a776d98eSRobert Mustacchi
3125a776d98eSRobert Mustacchi prev = cur;
3126a776d98eSRobert Mustacchi }
3127a776d98eSRobert Mustacchi
3128a776d98eSRobert Mustacchi cur = kmem_alloc(sizeof (mac_mtu_req_t), KM_SLEEP);
3129a776d98eSRobert Mustacchi cur->mtr_mtu = *mtup;
3130a776d98eSRobert Mustacchi cur->mtr_ref = 1;
3131a776d98eSRobert Mustacchi if (prev != NULL) {
3132a776d98eSRobert Mustacchi cur->mtr_nextp = prev->mtr_nextp;
3133a776d98eSRobert Mustacchi prev->mtr_nextp = cur;
3134a776d98eSRobert Mustacchi } else {
3135a776d98eSRobert Mustacchi cur->mtr_nextp = mip->mi_mtrp;
3136a776d98eSRobert Mustacchi mip->mi_mtrp = cur;
3137a776d98eSRobert Mustacchi }
3138a776d98eSRobert Mustacchi
3139a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3140a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3141a776d98eSRobert Mustacchi return (0);
3142a776d98eSRobert Mustacchi }
3143a776d98eSRobert Mustacchi
3144a776d98eSRobert Mustacchi int
mac_mtu_remove(mac_handle_t mh,uint32_t mtu)3145a776d98eSRobert Mustacchi mac_mtu_remove(mac_handle_t mh, uint32_t mtu)
3146a776d98eSRobert Mustacchi {
3147a776d98eSRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
3148a776d98eSRobert Mustacchi mac_mtu_req_t *cur, *prev;
3149a776d98eSRobert Mustacchi
3150a776d98eSRobert Mustacchi i_mac_perim_enter(mip);
3151a776d98eSRobert Mustacchi rw_enter(&mip->mi_rw_lock, RW_WRITER);
3152a776d98eSRobert Mustacchi
3153a776d98eSRobert Mustacchi prev = NULL;
3154a776d98eSRobert Mustacchi for (cur = mip->mi_mtrp; cur != NULL; cur = cur->mtr_nextp) {
3155a776d98eSRobert Mustacchi if (cur->mtr_mtu == mtu) {
3156a776d98eSRobert Mustacchi ASSERT(cur->mtr_ref > 0);
3157a776d98eSRobert Mustacchi cur->mtr_ref--;
3158a776d98eSRobert Mustacchi if (cur->mtr_ref == 0) {
3159a776d98eSRobert Mustacchi if (prev == NULL) {
3160a776d98eSRobert Mustacchi mip->mi_mtrp = cur->mtr_nextp;
3161a776d98eSRobert Mustacchi } else {
3162a776d98eSRobert Mustacchi prev->mtr_nextp = cur->mtr_nextp;
3163a776d98eSRobert Mustacchi }
3164a776d98eSRobert Mustacchi kmem_free(cur, sizeof (mac_mtu_req_t));
3165a776d98eSRobert Mustacchi }
3166a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3167a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3168a776d98eSRobert Mustacchi return (0);
3169a776d98eSRobert Mustacchi }
3170a776d98eSRobert Mustacchi
3171a776d98eSRobert Mustacchi prev = cur;
3172a776d98eSRobert Mustacchi }
3173a776d98eSRobert Mustacchi
3174a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock);
3175a776d98eSRobert Mustacchi i_mac_perim_exit(mip);
3176a776d98eSRobert Mustacchi return (ENOENT);
3177a776d98eSRobert Mustacchi }
3178a776d98eSRobert Mustacchi
3179a776d98eSRobert Mustacchi /*
3180ba2e4443Sseb * MAC Type Plugin functions.
3181ba2e4443Sseb */
3182ba2e4443Sseb
3183da14cebeSEric Cheng mactype_t *
mactype_getplugin(const char * pname)3184da14cebeSEric Cheng mactype_getplugin(const char *pname)
3185da14cebeSEric Cheng {
3186da14cebeSEric Cheng mactype_t *mtype = NULL;
3187da14cebeSEric Cheng boolean_t tried_modload = B_FALSE;
3188da14cebeSEric Cheng
3189da14cebeSEric Cheng mutex_enter(&i_mactype_lock);
3190da14cebeSEric Cheng
3191da14cebeSEric Cheng find_registered_mactype:
3192da14cebeSEric Cheng if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
3193da14cebeSEric Cheng (mod_hash_val_t *)&mtype) != 0) {
3194da14cebeSEric Cheng if (!tried_modload) {
3195da14cebeSEric Cheng /*
3196da14cebeSEric Cheng * If the plugin has not yet been loaded, then
3197da14cebeSEric Cheng * attempt to load it now. If modload() succeeds,
3198da14cebeSEric Cheng * the plugin should have registered using
3199da14cebeSEric Cheng * mactype_register(), in which case we can go back
3200da14cebeSEric Cheng * and attempt to find it again.
3201da14cebeSEric Cheng */
3202da14cebeSEric Cheng if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
3203da14cebeSEric Cheng tried_modload = B_TRUE;
3204da14cebeSEric Cheng goto find_registered_mactype;
3205da14cebeSEric Cheng }
3206da14cebeSEric Cheng }
3207da14cebeSEric Cheng } else {
3208da14cebeSEric Cheng /*
3209da14cebeSEric Cheng * Note that there's no danger that the plugin we've loaded
3210da14cebeSEric Cheng * could be unloaded between the modload() step and the
3211da14cebeSEric Cheng * reference count bump here, as we're holding
3212da14cebeSEric Cheng * i_mactype_lock, which mactype_unregister() also holds.
3213da14cebeSEric Cheng */
3214da14cebeSEric Cheng atomic_inc_32(&mtype->mt_ref);
3215da14cebeSEric Cheng }
3216da14cebeSEric Cheng
3217da14cebeSEric Cheng mutex_exit(&i_mactype_lock);
3218da14cebeSEric Cheng return (mtype);
3219da14cebeSEric Cheng }
3220da14cebeSEric Cheng
3221ba2e4443Sseb mactype_register_t *
mactype_alloc(uint_t mactype_version)3222ba2e4443Sseb mactype_alloc(uint_t mactype_version)
3223ba2e4443Sseb {
3224ba2e4443Sseb mactype_register_t *mtrp;
3225ba2e4443Sseb
3226ba2e4443Sseb /*
3227ba2e4443Sseb * Make sure there isn't a version mismatch between the plugin and
3228ba2e4443Sseb * the framework. In the future, if multiple versions are
3229ba2e4443Sseb * supported, this check could become more sophisticated.
3230ba2e4443Sseb */
3231ba2e4443Sseb if (mactype_version != MACTYPE_VERSION)
3232ba2e4443Sseb return (NULL);
3233ba2e4443Sseb
3234ba2e4443Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
3235ba2e4443Sseb mtrp->mtr_version = mactype_version;
3236ba2e4443Sseb return (mtrp);
3237ba2e4443Sseb }
3238ba2e4443Sseb
3239ba2e4443Sseb void
mactype_free(mactype_register_t * mtrp)3240ba2e4443Sseb mactype_free(mactype_register_t *mtrp)
3241ba2e4443Sseb {
3242ba2e4443Sseb kmem_free(mtrp, sizeof (mactype_register_t));
3243ba2e4443Sseb }
3244ba2e4443Sseb
3245ba2e4443Sseb int
mactype_register(mactype_register_t * mtrp)3246ba2e4443Sseb mactype_register(mactype_register_t *mtrp)
3247ba2e4443Sseb {
3248ba2e4443Sseb mactype_t *mtp;
3249ba2e4443Sseb mactype_ops_t *ops = mtrp->mtr_ops;
3250ba2e4443Sseb
3251ba2e4443Sseb /* Do some sanity checking before we register this MAC type. */
3252c08e5e1aSdr146992 if (mtrp->mtr_ident == NULL || ops == NULL)
3253ba2e4443Sseb return (EINVAL);
3254ba2e4443Sseb
3255ba2e4443Sseb /*
3256ba2e4443Sseb * Verify that all mandatory callbacks are set in the ops
3257ba2e4443Sseb * vector.
3258ba2e4443Sseb */
3259ba2e4443Sseb if (ops->mtops_unicst_verify == NULL ||
3260ba2e4443Sseb ops->mtops_multicst_verify == NULL ||
3261ba2e4443Sseb ops->mtops_sap_verify == NULL ||
3262ba2e4443Sseb ops->mtops_header == NULL ||
3263ba2e4443Sseb ops->mtops_header_info == NULL) {
3264ba2e4443Sseb return (EINVAL);
3265ba2e4443Sseb }
3266ba2e4443Sseb
3267ba2e4443Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
3268ba2e4443Sseb mtp->mt_ident = mtrp->mtr_ident;
3269ba2e4443Sseb mtp->mt_ops = *ops;
3270ba2e4443Sseb mtp->mt_type = mtrp->mtr_mactype;
32710ba2cbe9Sxc151355 mtp->mt_nativetype = mtrp->mtr_nativetype;
3272ba2e4443Sseb mtp->mt_addr_length = mtrp->mtr_addrlen;
3273ba2e4443Sseb if (mtrp->mtr_brdcst_addr != NULL) {
3274ba2e4443Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
3275ba2e4443Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
3276ba2e4443Sseb mtrp->mtr_addrlen);
3277ba2e4443Sseb }
3278ba2e4443Sseb
3279ba2e4443Sseb mtp->mt_stats = mtrp->mtr_stats;
3280ba2e4443Sseb mtp->mt_statcount = mtrp->mtr_statcount;
3281ba2e4443Sseb
32824045d941Ssowmini mtp->mt_mapping = mtrp->mtr_mapping;
32834045d941Ssowmini mtp->mt_mappingcount = mtrp->mtr_mappingcount;
32844045d941Ssowmini
3285ba2e4443Sseb if (mod_hash_insert(i_mactype_hash,
3286ba2e4443Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
3287ba2e4443Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
3288ba2e4443Sseb kmem_free(mtp, sizeof (*mtp));
3289ba2e4443Sseb return (EEXIST);
3290ba2e4443Sseb }
3291ba2e4443Sseb return (0);
3292ba2e4443Sseb }
3293ba2e4443Sseb
3294ba2e4443Sseb int
mactype_unregister(const char * ident)3295ba2e4443Sseb mactype_unregister(const char *ident)
3296ba2e4443Sseb {
3297ba2e4443Sseb mactype_t *mtp;
3298ba2e4443Sseb mod_hash_val_t val;
3299ba2e4443Sseb int err;
3300ba2e4443Sseb
3301ba2e4443Sseb /*
3302ba2e4443Sseb * Let's not allow MAC drivers to use this plugin while we're
3303bd7f69f6Sseb * trying to unregister it. Holding i_mactype_lock also prevents a
3304bd7f69f6Sseb * plugin from unregistering while a MAC driver is attempting to
3305bd7f69f6Sseb * hold a reference to it in i_mactype_getplugin().
3306ba2e4443Sseb */
3307bd7f69f6Sseb mutex_enter(&i_mactype_lock);
3308ba2e4443Sseb
3309ba2e4443Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
3310ba2e4443Sseb (mod_hash_val_t *)&mtp)) != 0) {
3311ba2e4443Sseb /* A plugin is trying to unregister, but it never registered. */
3312bd7f69f6Sseb err = ENXIO;
3313bd7f69f6Sseb goto done;
3314ba2e4443Sseb }
3315ba2e4443Sseb
3316bd7f69f6Sseb if (mtp->mt_ref != 0) {
3317bd7f69f6Sseb err = EBUSY;
3318bd7f69f6Sseb goto done;
3319ba2e4443Sseb }
3320ba2e4443Sseb
3321ba2e4443Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
3322ba2e4443Sseb ASSERT(err == 0);
3323ba2e4443Sseb if (err != 0) {
3324ba2e4443Sseb /* This should never happen, thus the ASSERT() above. */
3325bd7f69f6Sseb err = EINVAL;
3326bd7f69f6Sseb goto done;
3327ba2e4443Sseb }
3328ba2e4443Sseb ASSERT(mtp == (mactype_t *)val);
3329ba2e4443Sseb
33302b24ab6bSSebastien Roy if (mtp->mt_brdcst_addr != NULL)
3331ba2e4443Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
3332ba2e4443Sseb kmem_free(mtp, sizeof (mactype_t));
3333bd7f69f6Sseb done:
3334bd7f69f6Sseb mutex_exit(&i_mactype_lock);
3335bd7f69f6Sseb return (err);
3336ba2e4443Sseb }
3337e7801d59Ssowmini
3338da14cebeSEric Cheng /*
33390dc2366fSVenugopal Iyer * Checks the size of the value size specified for a property as
33400dc2366fSVenugopal Iyer * part of a property operation. Returns B_TRUE if the size is
33410dc2366fSVenugopal Iyer * correct, B_FALSE otherwise.
33420dc2366fSVenugopal Iyer */
33430dc2366fSVenugopal Iyer boolean_t
mac_prop_check_size(mac_prop_id_t id,uint_t valsize,boolean_t is_range)33440dc2366fSVenugopal Iyer mac_prop_check_size(mac_prop_id_t id, uint_t valsize, boolean_t is_range)
33450dc2366fSVenugopal Iyer {
33460dc2366fSVenugopal Iyer uint_t minsize = 0;
33470dc2366fSVenugopal Iyer
33480dc2366fSVenugopal Iyer if (is_range)
33490dc2366fSVenugopal Iyer return (valsize >= sizeof (mac_propval_range_t));
33500dc2366fSVenugopal Iyer
33510dc2366fSVenugopal Iyer switch (id) {
33520dc2366fSVenugopal Iyer case MAC_PROP_ZONE:
33530dc2366fSVenugopal Iyer minsize = sizeof (dld_ioc_zid_t);
33540dc2366fSVenugopal Iyer break;
33550dc2366fSVenugopal Iyer case MAC_PROP_AUTOPUSH:
33560dc2366fSVenugopal Iyer if (valsize != 0)
33570dc2366fSVenugopal Iyer minsize = sizeof (struct dlautopush);
33580dc2366fSVenugopal Iyer break;
33590dc2366fSVenugopal Iyer case MAC_PROP_TAGMODE:
33600dc2366fSVenugopal Iyer minsize = sizeof (link_tagmode_t);
33610dc2366fSVenugopal Iyer break;
33620dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE:
33630dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE_EFF:
33640dc2366fSVenugopal Iyer minsize = sizeof (mac_resource_props_t);
33650dc2366fSVenugopal Iyer break;
33660dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX:
33670dc2366fSVenugopal Iyer minsize = sizeof (link_duplex_t);
33680dc2366fSVenugopal Iyer break;
33690dc2366fSVenugopal Iyer case MAC_PROP_SPEED:
33700dc2366fSVenugopal Iyer minsize = sizeof (uint64_t);
33710dc2366fSVenugopal Iyer break;
33720dc2366fSVenugopal Iyer case MAC_PROP_STATUS:
33730dc2366fSVenugopal Iyer minsize = sizeof (link_state_t);
33740dc2366fSVenugopal Iyer break;
33750dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG:
33760dc2366fSVenugopal Iyer case MAC_PROP_EN_AUTONEG:
33770dc2366fSVenugopal Iyer minsize = sizeof (uint8_t);
33780dc2366fSVenugopal Iyer break;
33790dc2366fSVenugopal Iyer case MAC_PROP_MTU:
33800dc2366fSVenugopal Iyer case MAC_PROP_LLIMIT:
33810dc2366fSVenugopal Iyer case MAC_PROP_LDECAY:
33820dc2366fSVenugopal Iyer minsize = sizeof (uint32_t);
33830dc2366fSVenugopal Iyer break;
33840dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL:
33850dc2366fSVenugopal Iyer minsize = sizeof (link_flowctrl_t);
33860dc2366fSVenugopal Iyer break;
3387d77e6e0fSPaul Winder case MAC_PROP_ADV_FEC_CAP:
3388d77e6e0fSPaul Winder case MAC_PROP_EN_FEC_CAP:
3389d77e6e0fSPaul Winder minsize = sizeof (link_fec_t);
3390d77e6e0fSPaul Winder break;
33912aaafd60SRobert Mustacchi case MAC_PROP_ADV_400GFDX_CAP:
33922aaafd60SRobert Mustacchi case MAC_PROP_EN_400GFDX_CAP:
33932aaafd60SRobert Mustacchi case MAC_PROP_ADV_200GFDX_CAP:
33942aaafd60SRobert Mustacchi case MAC_PROP_EN_200GFDX_CAP:
33953bc4925dSGarrett D'Amore case MAC_PROP_ADV_100GFDX_CAP:
33963bc4925dSGarrett D'Amore case MAC_PROP_EN_100GFDX_CAP:
33973d75a287SRobert Mustacchi case MAC_PROP_ADV_50GFDX_CAP:
33983d75a287SRobert Mustacchi case MAC_PROP_EN_50GFDX_CAP:
33993bc4925dSGarrett D'Amore case MAC_PROP_ADV_40GFDX_CAP:
34003bc4925dSGarrett D'Amore case MAC_PROP_EN_40GFDX_CAP:
34013d75a287SRobert Mustacchi case MAC_PROP_ADV_25GFDX_CAP:
34023d75a287SRobert Mustacchi case MAC_PROP_EN_25GFDX_CAP:
34030dc2366fSVenugopal Iyer case MAC_PROP_ADV_10GFDX_CAP:
34040dc2366fSVenugopal Iyer case MAC_PROP_EN_10GFDX_CAP:
34052aaafd60SRobert Mustacchi case MAC_PROP_ADV_5000FDX_CAP:
34062aaafd60SRobert Mustacchi case MAC_PROP_EN_5000FDX_CAP:
34072aaafd60SRobert Mustacchi case MAC_PROP_ADV_2500FDX_CAP:
34082aaafd60SRobert Mustacchi case MAC_PROP_EN_2500FDX_CAP:
34090dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP:
34100dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP:
34110dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP:
34120dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP:
34132aaafd60SRobert Mustacchi case MAC_PROP_ADV_100T4_CAP:
34142aaafd60SRobert Mustacchi case MAC_PROP_EN_100T4_CAP:
34150dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP:
34160dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP:
34170dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP:
34180dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP:
34190dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP:
34200dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP:
34210dc2366fSVenugopal Iyer minsize = sizeof (uint8_t);
34220dc2366fSVenugopal Iyer break;
34230dc2366fSVenugopal Iyer case MAC_PROP_PVID:
34240dc2366fSVenugopal Iyer minsize = sizeof (uint16_t);
34250dc2366fSVenugopal Iyer break;
34260dc2366fSVenugopal Iyer case MAC_PROP_IPTUN_HOPLIMIT:
34270dc2366fSVenugopal Iyer minsize = sizeof (uint32_t);
34280dc2366fSVenugopal Iyer break;
34290dc2366fSVenugopal Iyer case MAC_PROP_IPTUN_ENCAPLIMIT:
34300dc2366fSVenugopal Iyer minsize = sizeof (uint32_t);
34310dc2366fSVenugopal Iyer break;
34320dc2366fSVenugopal Iyer case MAC_PROP_MAX_TX_RINGS_AVAIL:
34330dc2366fSVenugopal Iyer case MAC_PROP_MAX_RX_RINGS_AVAIL:
34340dc2366fSVenugopal Iyer case MAC_PROP_MAX_RXHWCLNT_AVAIL:
34350dc2366fSVenugopal Iyer case MAC_PROP_MAX_TXHWCLNT_AVAIL:
34360dc2366fSVenugopal Iyer minsize = sizeof (uint_t);
34370dc2366fSVenugopal Iyer break;
34380dc2366fSVenugopal Iyer case MAC_PROP_WL_ESSID:
34390dc2366fSVenugopal Iyer minsize = sizeof (wl_linkstatus_t);
34400dc2366fSVenugopal Iyer break;
34410dc2366fSVenugopal Iyer case MAC_PROP_WL_BSSID:
34420dc2366fSVenugopal Iyer minsize = sizeof (wl_bssid_t);
34430dc2366fSVenugopal Iyer break;
34440dc2366fSVenugopal Iyer case MAC_PROP_WL_BSSTYPE:
34450dc2366fSVenugopal Iyer minsize = sizeof (wl_bss_type_t);
34460dc2366fSVenugopal Iyer break;
34470dc2366fSVenugopal Iyer case MAC_PROP_WL_LINKSTATUS:
34480dc2366fSVenugopal Iyer minsize = sizeof (wl_linkstatus_t);
34490dc2366fSVenugopal Iyer break;
34500dc2366fSVenugopal Iyer case MAC_PROP_WL_DESIRED_RATES:
34510dc2366fSVenugopal Iyer minsize = sizeof (wl_rates_t);
34520dc2366fSVenugopal Iyer break;
34530dc2366fSVenugopal Iyer case MAC_PROP_WL_SUPPORTED_RATES:
34540dc2366fSVenugopal Iyer minsize = sizeof (wl_rates_t);
34550dc2366fSVenugopal Iyer break;
34560dc2366fSVenugopal Iyer case MAC_PROP_WL_AUTH_MODE:
34570dc2366fSVenugopal Iyer minsize = sizeof (wl_authmode_t);
34580dc2366fSVenugopal Iyer break;
34590dc2366fSVenugopal Iyer case MAC_PROP_WL_ENCRYPTION:
34600dc2366fSVenugopal Iyer minsize = sizeof (wl_encryption_t);
34610dc2366fSVenugopal Iyer break;
34620dc2366fSVenugopal Iyer case MAC_PROP_WL_RSSI:
34630dc2366fSVenugopal Iyer minsize = sizeof (wl_rssi_t);
34640dc2366fSVenugopal Iyer break;
34650dc2366fSVenugopal Iyer case MAC_PROP_WL_PHY_CONFIG:
34660dc2366fSVenugopal Iyer minsize = sizeof (wl_phy_conf_t);
34670dc2366fSVenugopal Iyer break;
34680dc2366fSVenugopal Iyer case MAC_PROP_WL_CAPABILITY:
34690dc2366fSVenugopal Iyer minsize = sizeof (wl_capability_t);
34700dc2366fSVenugopal Iyer break;
34710dc2366fSVenugopal Iyer case MAC_PROP_WL_WPA:
34720dc2366fSVenugopal Iyer minsize = sizeof (wl_wpa_t);
34730dc2366fSVenugopal Iyer break;
34740dc2366fSVenugopal Iyer case MAC_PROP_WL_SCANRESULTS:
34750dc2366fSVenugopal Iyer minsize = sizeof (wl_wpa_ess_t);
34760dc2366fSVenugopal Iyer break;
34770dc2366fSVenugopal Iyer case MAC_PROP_WL_POWER_MODE:
34780dc2366fSVenugopal Iyer minsize = sizeof (wl_ps_mode_t);
34790dc2366fSVenugopal Iyer break;
34800dc2366fSVenugopal Iyer case MAC_PROP_WL_RADIO:
34810dc2366fSVenugopal Iyer minsize = sizeof (wl_radio_t);
34820dc2366fSVenugopal Iyer break;
34830dc2366fSVenugopal Iyer case MAC_PROP_WL_ESS_LIST:
34840dc2366fSVenugopal Iyer minsize = sizeof (wl_ess_list_t);
34850dc2366fSVenugopal Iyer break;
34860dc2366fSVenugopal Iyer case MAC_PROP_WL_KEY_TAB:
34870dc2366fSVenugopal Iyer minsize = sizeof (wl_wep_key_tab_t);
34880dc2366fSVenugopal Iyer break;
34890dc2366fSVenugopal Iyer case MAC_PROP_WL_CREATE_IBSS:
34900dc2366fSVenugopal Iyer minsize = sizeof (wl_create_ibss_t);
34910dc2366fSVenugopal Iyer break;
34920dc2366fSVenugopal Iyer case MAC_PROP_WL_SETOPTIE:
34930dc2366fSVenugopal Iyer minsize = sizeof (wl_wpa_ie_t);
34940dc2366fSVenugopal Iyer break;
34950dc2366fSVenugopal Iyer case MAC_PROP_WL_DELKEY:
34960dc2366fSVenugopal Iyer minsize = sizeof (wl_del_key_t);
34970dc2366fSVenugopal Iyer break;
34980dc2366fSVenugopal Iyer case MAC_PROP_WL_KEY:
34990dc2366fSVenugopal Iyer minsize = sizeof (wl_key_t);
35000dc2366fSVenugopal Iyer break;
35010dc2366fSVenugopal Iyer case MAC_PROP_WL_MLME:
35020dc2366fSVenugopal Iyer minsize = sizeof (wl_mlme_t);
35030dc2366fSVenugopal Iyer break;
350410a40492SRobert Mustacchi case MAC_PROP_VN_PROMISC_FILTERED:
350510a40492SRobert Mustacchi minsize = sizeof (boolean_t);
350610a40492SRobert Mustacchi break;
3507dd72704bSRobert Mustacchi case MAC_PROP_MEDIA:
3508dd72704bSRobert Mustacchi /*
3509dd72704bSRobert Mustacchi * Our assumption is that each class of device uses an enum and
3510dd72704bSRobert Mustacchi * that all enums will be the same size so it is OK to use a
3511dd72704bSRobert Mustacchi * single one.
3512dd72704bSRobert Mustacchi */
3513dd72704bSRobert Mustacchi minsize = sizeof (mac_ether_media_t);
3514dd72704bSRobert Mustacchi break;
35150dc2366fSVenugopal Iyer }
35160dc2366fSVenugopal Iyer
35170dc2366fSVenugopal Iyer return (valsize >= minsize);
35180dc2366fSVenugopal Iyer }
35190dc2366fSVenugopal Iyer
35200dc2366fSVenugopal Iyer /*
35210dc2366fSVenugopal Iyer * mac_set_prop() sets MAC or hardware driver properties:
35220dc2366fSVenugopal Iyer *
35230dc2366fSVenugopal Iyer * - MAC-managed properties such as resource properties include maxbw,
35240dc2366fSVenugopal Iyer * priority, and cpu binding list, as well as the default port VID
35250dc2366fSVenugopal Iyer * used by bridging. These properties are consumed by the MAC layer
35260dc2366fSVenugopal Iyer * itself and not passed down to the driver. For resource control
35270dc2366fSVenugopal Iyer * properties, this function invokes mac_set_resources() which will
35280dc2366fSVenugopal Iyer * cache the property value in mac_impl_t and may call
35290dc2366fSVenugopal Iyer * mac_client_set_resource() to update property value of the primary
35304eaa4710SRishi Srivatsavai * mac client, if it exists.
35310dc2366fSVenugopal Iyer *
35320dc2366fSVenugopal Iyer * - Properties which act on the hardware and must be passed to the
35330dc2366fSVenugopal Iyer * driver, such as MTU, through the driver's mc_setprop() entry point.
3534da14cebeSEric Cheng */
3535e7801d59Ssowmini int
mac_set_prop(mac_handle_t mh,mac_prop_id_t id,char * name,void * val,uint_t valsize)35360dc2366fSVenugopal Iyer mac_set_prop(mac_handle_t mh, mac_prop_id_t id, char *name, void *val,
35370dc2366fSVenugopal Iyer uint_t valsize)
3538e7801d59Ssowmini {
3539e7801d59Ssowmini int err = ENOTSUP;
3540e7801d59Ssowmini mac_impl_t *mip = (mac_impl_t *)mh;
3541e7801d59Ssowmini
3542da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(mh));
3543da14cebeSEric Cheng
35440dc2366fSVenugopal Iyer switch (id) {
35450dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE: {
35460dc2366fSVenugopal Iyer mac_resource_props_t *mrp;
3547da14cebeSEric Cheng
35480dc2366fSVenugopal Iyer /* call mac_set_resources() for MAC properties */
35490dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (mac_resource_props_t));
35500dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
35510dc2366fSVenugopal Iyer bcopy(val, mrp, sizeof (*mrp));
35520dc2366fSVenugopal Iyer err = mac_set_resources(mh, mrp);
35530dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp));
35544eaa4710SRishi Srivatsavai break;
3555da14cebeSEric Cheng }
35564eaa4710SRishi Srivatsavai
35574eaa4710SRishi Srivatsavai case MAC_PROP_PVID:
35580dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint16_t));
35590dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_VNIC)
35604eaa4710SRishi Srivatsavai return (EINVAL);
35614eaa4710SRishi Srivatsavai err = mac_set_pvid(mh, *(uint16_t *)val);
35624eaa4710SRishi Srivatsavai break;
35634eaa4710SRishi Srivatsavai
3564986cab2cSGirish Moodalbail case MAC_PROP_MTU: {
3565986cab2cSGirish Moodalbail uint32_t mtu;
3566986cab2cSGirish Moodalbail
35670dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint32_t));
3568986cab2cSGirish Moodalbail bcopy(val, &mtu, sizeof (mtu));
3569986cab2cSGirish Moodalbail err = mac_set_mtu(mh, mtu, NULL);
3570986cab2cSGirish Moodalbail break;
3571986cab2cSGirish Moodalbail }
35724eaa4710SRishi Srivatsavai
35734eaa4710SRishi Srivatsavai case MAC_PROP_LLIMIT:
35744eaa4710SRishi Srivatsavai case MAC_PROP_LDECAY: {
35754eaa4710SRishi Srivatsavai uint32_t learnval;
35764eaa4710SRishi Srivatsavai
35774eaa4710SRishi Srivatsavai if (valsize < sizeof (learnval) ||
35784eaa4710SRishi Srivatsavai (mip->mi_state_flags & MIS_IS_VNIC))
35794eaa4710SRishi Srivatsavai return (EINVAL);
35804eaa4710SRishi Srivatsavai bcopy(val, &learnval, sizeof (learnval));
35810dc2366fSVenugopal Iyer if (learnval == 0 && id == MAC_PROP_LDECAY)
35824eaa4710SRishi Srivatsavai return (EINVAL);
35830dc2366fSVenugopal Iyer if (id == MAC_PROP_LLIMIT)
35844eaa4710SRishi Srivatsavai mip->mi_llimit = learnval;
35854eaa4710SRishi Srivatsavai else
35864eaa4710SRishi Srivatsavai mip->mi_ldecay = learnval;
35874eaa4710SRishi Srivatsavai err = 0;
35884eaa4710SRishi Srivatsavai break;
35894eaa4710SRishi Srivatsavai }
35904eaa4710SRishi Srivatsavai
3591d77e6e0fSPaul Winder case MAC_PROP_ADV_FEC_CAP:
3592d77e6e0fSPaul Winder case MAC_PROP_EN_FEC_CAP: {
3593d77e6e0fSPaul Winder link_fec_t fec;
3594d77e6e0fSPaul Winder
3595d77e6e0fSPaul Winder ASSERT(valsize >= sizeof (link_fec_t));
3596d77e6e0fSPaul Winder
3597d77e6e0fSPaul Winder /*
3598d77e6e0fSPaul Winder * fec cannot be zero, and auto must be set exclusively.
3599d77e6e0fSPaul Winder */
3600d77e6e0fSPaul Winder bcopy(val, &fec, sizeof (link_fec_t));
3601d77e6e0fSPaul Winder if (fec == 0)
3602d77e6e0fSPaul Winder return (EINVAL);
3603d77e6e0fSPaul Winder if ((fec & LINK_FEC_AUTO) != 0 && (fec & ~LINK_FEC_AUTO) != 0)
3604d77e6e0fSPaul Winder return (EINVAL);
3605d77e6e0fSPaul Winder
3606d77e6e0fSPaul Winder if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
3607d77e6e0fSPaul Winder err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
3608d77e6e0fSPaul Winder name, id, valsize, val);
3609d77e6e0fSPaul Winder }
3610d77e6e0fSPaul Winder break;
3611d77e6e0fSPaul Winder }
3612d77e6e0fSPaul Winder
3613986cab2cSGirish Moodalbail default:
3614986cab2cSGirish Moodalbail /* For other driver properties, call driver's callback */
3615e7801d59Ssowmini if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
3616e7801d59Ssowmini err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
36170dc2366fSVenugopal Iyer name, id, valsize, val);
3618e7801d59Ssowmini }
3619986cab2cSGirish Moodalbail }
3620e7801d59Ssowmini return (err);
3621e7801d59Ssowmini }
3622e7801d59Ssowmini
3623da14cebeSEric Cheng /*
36240dc2366fSVenugopal Iyer * mac_get_prop() gets MAC or device driver properties.
3625da14cebeSEric Cheng *
3626da14cebeSEric Cheng * If the property is a driver property, mac_get_prop() calls driver's callback
36270dc2366fSVenugopal Iyer * entry point to get it.
36280dc2366fSVenugopal Iyer * If the property is a MAC property, mac_get_prop() invokes mac_get_resources()
3629da14cebeSEric Cheng * which returns the cached value in mac_impl_t.
3630da14cebeSEric Cheng */
3631e7801d59Ssowmini int
mac_get_prop(mac_handle_t mh,mac_prop_id_t id,char * name,void * val,uint_t valsize)36320dc2366fSVenugopal Iyer mac_get_prop(mac_handle_t mh, mac_prop_id_t id, char *name, void *val,
36330dc2366fSVenugopal Iyer uint_t valsize)
3634e7801d59Ssowmini {
3635e7801d59Ssowmini int err = ENOTSUP;
3636e7801d59Ssowmini mac_impl_t *mip = (mac_impl_t *)mh;
36370dc2366fSVenugopal Iyer uint_t rings;
36380dc2366fSVenugopal Iyer uint_t vlinks;
3639f0f2c3a5SGirish Moodalbail
36400dc2366fSVenugopal Iyer bzero(val, valsize);
3641e7801d59Ssowmini
36420dc2366fSVenugopal Iyer switch (id) {
36430dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE: {
36440dc2366fSVenugopal Iyer mac_resource_props_t *mrp;
3645da14cebeSEric Cheng
36464eaa4710SRishi Srivatsavai /* If mac property, read from cache */
36470dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (mac_resource_props_t));
36480dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
36490dc2366fSVenugopal Iyer mac_get_resources(mh, mrp);
36500dc2366fSVenugopal Iyer bcopy(mrp, val, sizeof (*mrp));
36510dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp));
36520dc2366fSVenugopal Iyer return (0);
36530dc2366fSVenugopal Iyer }
36540dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE_EFF: {
36550dc2366fSVenugopal Iyer mac_resource_props_t *mrp;
36560dc2366fSVenugopal Iyer
36570dc2366fSVenugopal Iyer /* If mac effective property, read from client */
36580dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (mac_resource_props_t));
36590dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
36600dc2366fSVenugopal Iyer mac_get_effective_resources(mh, mrp);
36610dc2366fSVenugopal Iyer bcopy(mrp, val, sizeof (*mrp));
36620dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp));
3663da14cebeSEric Cheng return (0);
3664da14cebeSEric Cheng }
3665da14cebeSEric Cheng
36664eaa4710SRishi Srivatsavai case MAC_PROP_PVID:
36670dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint16_t));
36680dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_VNIC)
36694eaa4710SRishi Srivatsavai return (EINVAL);
36704eaa4710SRishi Srivatsavai *(uint16_t *)val = mac_get_pvid(mh);
36714eaa4710SRishi Srivatsavai return (0);
36724eaa4710SRishi Srivatsavai
36734eaa4710SRishi Srivatsavai case MAC_PROP_LLIMIT:
36744eaa4710SRishi Srivatsavai case MAC_PROP_LDECAY:
36750dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint32_t));
36760dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_VNIC)
36774eaa4710SRishi Srivatsavai return (EINVAL);
36780dc2366fSVenugopal Iyer if (id == MAC_PROP_LLIMIT)
36794eaa4710SRishi Srivatsavai bcopy(&mip->mi_llimit, val, sizeof (mip->mi_llimit));
36804eaa4710SRishi Srivatsavai else
36814eaa4710SRishi Srivatsavai bcopy(&mip->mi_ldecay, val, sizeof (mip->mi_ldecay));
36824eaa4710SRishi Srivatsavai return (0);
36834eaa4710SRishi Srivatsavai
3684f0f2c3a5SGirish Moodalbail case MAC_PROP_MTU: {
3685f0f2c3a5SGirish Moodalbail uint32_t sdu;
3686f0f2c3a5SGirish Moodalbail
36870dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint32_t));
36881eee170aSErik Nordmark mac_sdu_get2(mh, NULL, &sdu, NULL);
36894045d941Ssowmini bcopy(&sdu, val, sizeof (sdu));
3690986cab2cSGirish Moodalbail
36914045d941Ssowmini return (0);
36924045d941Ssowmini }
36930dc2366fSVenugopal Iyer case MAC_PROP_STATUS: {
36940dc2366fSVenugopal Iyer link_state_t link_state;
36950dc2366fSVenugopal Iyer
36964045d941Ssowmini if (valsize < sizeof (link_state))
36974045d941Ssowmini return (EINVAL);
36984045d941Ssowmini link_state = mac_link_get(mh);
36994045d941Ssowmini bcopy(&link_state, val, sizeof (link_state));
37000dc2366fSVenugopal Iyer
37014045d941Ssowmini return (0);
37020dc2366fSVenugopal Iyer }
37030dc2366fSVenugopal Iyer
37040dc2366fSVenugopal Iyer case MAC_PROP_MAX_RX_RINGS_AVAIL:
37050dc2366fSVenugopal Iyer case MAC_PROP_MAX_TX_RINGS_AVAIL:
37060dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint_t));
37070dc2366fSVenugopal Iyer rings = id == MAC_PROP_MAX_RX_RINGS_AVAIL ?
37080dc2366fSVenugopal Iyer mac_rxavail_get(mh) : mac_txavail_get(mh);
37090dc2366fSVenugopal Iyer bcopy(&rings, val, sizeof (uint_t));
37100dc2366fSVenugopal Iyer return (0);
37110dc2366fSVenugopal Iyer
37120dc2366fSVenugopal Iyer case MAC_PROP_MAX_RXHWCLNT_AVAIL:
37130dc2366fSVenugopal Iyer case MAC_PROP_MAX_TXHWCLNT_AVAIL:
37140dc2366fSVenugopal Iyer ASSERT(valsize >= sizeof (uint_t));
37150dc2366fSVenugopal Iyer vlinks = id == MAC_PROP_MAX_RXHWCLNT_AVAIL ?
37160dc2366fSVenugopal Iyer mac_rxhwlnksavail_get(mh) : mac_txhwlnksavail_get(mh);
37170dc2366fSVenugopal Iyer bcopy(&vlinks, val, sizeof (uint_t));
37180dc2366fSVenugopal Iyer return (0);
37190dc2366fSVenugopal Iyer
37200dc2366fSVenugopal Iyer case MAC_PROP_RXRINGSRANGE:
37210dc2366fSVenugopal Iyer case MAC_PROP_TXRINGSRANGE:
37220dc2366fSVenugopal Iyer /*
37230dc2366fSVenugopal Iyer * The value for these properties are returned through
37240dc2366fSVenugopal Iyer * the MAC_PROP_RESOURCE property.
37250dc2366fSVenugopal Iyer */
37260dc2366fSVenugopal Iyer return (0);
37270dc2366fSVenugopal Iyer
37284045d941Ssowmini default:
37294045d941Ssowmini break;
3730da14cebeSEric Cheng
37314045d941Ssowmini }
37320dc2366fSVenugopal Iyer
3733da14cebeSEric Cheng /* If driver property, request from driver */
37340dc2366fSVenugopal Iyer if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
37350dc2366fSVenugopal Iyer err = mip->mi_callbacks->mc_getprop(mip->mi_driver, name, id,
37360dc2366fSVenugopal Iyer valsize, val);
3737e7801d59Ssowmini }
37380dc2366fSVenugopal Iyer
3739e7801d59Ssowmini return (err);
3740e7801d59Ssowmini }
3741e7801d59Ssowmini
37420dc2366fSVenugopal Iyer /*
37430dc2366fSVenugopal Iyer * Helper function to initialize the range structure for use in
37440dc2366fSVenugopal Iyer * mac_get_prop. If the type can be other than uint32, we can
37450dc2366fSVenugopal Iyer * pass that as an arg.
37460dc2366fSVenugopal Iyer */
37470dc2366fSVenugopal Iyer static void
_mac_set_range(mac_propval_range_t * range,uint32_t min,uint32_t max)37480dc2366fSVenugopal Iyer _mac_set_range(mac_propval_range_t *range, uint32_t min, uint32_t max)
37490dc2366fSVenugopal Iyer {
37500dc2366fSVenugopal Iyer range->mpr_count = 1;
37510dc2366fSVenugopal Iyer range->mpr_type = MAC_PROPVAL_UINT32;
37520dc2366fSVenugopal Iyer range->mpr_range_uint32[0].mpur_min = min;
37530dc2366fSVenugopal Iyer range->mpr_range_uint32[0].mpur_max = max;
37540dc2366fSVenugopal Iyer }
37550dc2366fSVenugopal Iyer
37560dc2366fSVenugopal Iyer /*
37570dc2366fSVenugopal Iyer * Returns information about the specified property, such as default
37580dc2366fSVenugopal Iyer * values or permissions.
37590dc2366fSVenugopal Iyer */
37600dc2366fSVenugopal Iyer int
mac_prop_info(mac_handle_t mh,mac_prop_id_t id,char * name,void * default_val,uint_t default_size,mac_propval_range_t * range,uint_t * perm)37610dc2366fSVenugopal Iyer mac_prop_info(mac_handle_t mh, mac_prop_id_t id, char *name,
37620dc2366fSVenugopal Iyer void *default_val, uint_t default_size, mac_propval_range_t *range,
37630dc2366fSVenugopal Iyer uint_t *perm)
37640dc2366fSVenugopal Iyer {
37650dc2366fSVenugopal Iyer mac_prop_info_state_t state;
37660dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh;
37670dc2366fSVenugopal Iyer uint_t max;
37680dc2366fSVenugopal Iyer
37690dc2366fSVenugopal Iyer /*
37700dc2366fSVenugopal Iyer * A property is read/write by default unless the driver says
37710dc2366fSVenugopal Iyer * otherwise.
37720dc2366fSVenugopal Iyer */
37730dc2366fSVenugopal Iyer if (perm != NULL)
37740dc2366fSVenugopal Iyer *perm = MAC_PROP_PERM_RW;
37750dc2366fSVenugopal Iyer
37760dc2366fSVenugopal Iyer if (default_val != NULL)
37770dc2366fSVenugopal Iyer bzero(default_val, default_size);
37780dc2366fSVenugopal Iyer
37790dc2366fSVenugopal Iyer /*
37800dc2366fSVenugopal Iyer * First, handle framework properties for which we don't need to
37810dc2366fSVenugopal Iyer * involve the driver.
37820dc2366fSVenugopal Iyer */
37830dc2366fSVenugopal Iyer switch (id) {
37840dc2366fSVenugopal Iyer case MAC_PROP_RESOURCE:
37850dc2366fSVenugopal Iyer case MAC_PROP_PVID:
37860dc2366fSVenugopal Iyer case MAC_PROP_LLIMIT:
37870dc2366fSVenugopal Iyer case MAC_PROP_LDECAY:
37880dc2366fSVenugopal Iyer return (0);
37890dc2366fSVenugopal Iyer
37900dc2366fSVenugopal Iyer case MAC_PROP_MAX_RX_RINGS_AVAIL:
37910dc2366fSVenugopal Iyer case MAC_PROP_MAX_TX_RINGS_AVAIL:
37920dc2366fSVenugopal Iyer case MAC_PROP_MAX_RXHWCLNT_AVAIL:
37930dc2366fSVenugopal Iyer case MAC_PROP_MAX_TXHWCLNT_AVAIL:
37940dc2366fSVenugopal Iyer if (perm != NULL)
37950dc2366fSVenugopal Iyer *perm = MAC_PROP_PERM_READ;
37960dc2366fSVenugopal Iyer return (0);
37970dc2366fSVenugopal Iyer
37980dc2366fSVenugopal Iyer case MAC_PROP_RXRINGSRANGE:
37990dc2366fSVenugopal Iyer case MAC_PROP_TXRINGSRANGE:
38000dc2366fSVenugopal Iyer /*
38010dc2366fSVenugopal Iyer * Currently, we support range for RX and TX rings properties.
38020dc2366fSVenugopal Iyer * When we extend this support to maxbw, cpus and priority,
38030dc2366fSVenugopal Iyer * we should move this to mac_get_resources.
38040dc2366fSVenugopal Iyer * There is no default value for RX or TX rings.
38050dc2366fSVenugopal Iyer */
38060dc2366fSVenugopal Iyer if ((mip->mi_state_flags & MIS_IS_VNIC) &&
38070dc2366fSVenugopal Iyer mac_is_vnic_primary(mh)) {
38080dc2366fSVenugopal Iyer /*
38090dc2366fSVenugopal Iyer * We don't support setting rings for a VLAN
38100dc2366fSVenugopal Iyer * data link because it shares its ring with the
38110dc2366fSVenugopal Iyer * primary MAC client.
38120dc2366fSVenugopal Iyer */
38130dc2366fSVenugopal Iyer if (perm != NULL)
38140dc2366fSVenugopal Iyer *perm = MAC_PROP_PERM_READ;
38150dc2366fSVenugopal Iyer if (range != NULL)
38160dc2366fSVenugopal Iyer range->mpr_count = 0;
38170dc2366fSVenugopal Iyer } else if (range != NULL) {
38180dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_VNIC)
38190dc2366fSVenugopal Iyer mh = mac_get_lower_mac_handle(mh);
38200dc2366fSVenugopal Iyer mip = (mac_impl_t *)mh;
38210dc2366fSVenugopal Iyer if ((id == MAC_PROP_RXRINGSRANGE &&
38220dc2366fSVenugopal Iyer mip->mi_rx_group_type == MAC_GROUP_TYPE_STATIC) ||
38230dc2366fSVenugopal Iyer (id == MAC_PROP_TXRINGSRANGE &&
38240dc2366fSVenugopal Iyer mip->mi_tx_group_type == MAC_GROUP_TYPE_STATIC)) {
38250dc2366fSVenugopal Iyer if (id == MAC_PROP_RXRINGSRANGE) {
38260dc2366fSVenugopal Iyer if ((mac_rxhwlnksavail_get(mh) +
38270dc2366fSVenugopal Iyer mac_rxhwlnksrsvd_get(mh)) <= 1) {
38280dc2366fSVenugopal Iyer /*
38290dc2366fSVenugopal Iyer * doesn't support groups or
38300dc2366fSVenugopal Iyer * rings
38310dc2366fSVenugopal Iyer */
38320dc2366fSVenugopal Iyer range->mpr_count = 0;
38330dc2366fSVenugopal Iyer } else {
38340dc2366fSVenugopal Iyer /*
38350dc2366fSVenugopal Iyer * supports specifying groups,
38360dc2366fSVenugopal Iyer * but not rings
38370dc2366fSVenugopal Iyer */
38380dc2366fSVenugopal Iyer _mac_set_range(range, 0, 0);
38390dc2366fSVenugopal Iyer }
38400dc2366fSVenugopal Iyer } else {
38410dc2366fSVenugopal Iyer if ((mac_txhwlnksavail_get(mh) +
38420dc2366fSVenugopal Iyer mac_txhwlnksrsvd_get(mh)) <= 1) {
38430dc2366fSVenugopal Iyer /*
38440dc2366fSVenugopal Iyer * doesn't support groups or
38450dc2366fSVenugopal Iyer * rings
38460dc2366fSVenugopal Iyer */
38470dc2366fSVenugopal Iyer range->mpr_count = 0;
38480dc2366fSVenugopal Iyer } else {
38490dc2366fSVenugopal Iyer /*
38500dc2366fSVenugopal Iyer * supports specifying groups,
38510dc2366fSVenugopal Iyer * but not rings
38520dc2366fSVenugopal Iyer */
38530dc2366fSVenugopal Iyer _mac_set_range(range, 0, 0);
38540dc2366fSVenugopal Iyer }
38550dc2366fSVenugopal Iyer }
38560dc2366fSVenugopal Iyer } else {
38570dc2366fSVenugopal Iyer max = id == MAC_PROP_RXRINGSRANGE ?
38580dc2366fSVenugopal Iyer mac_rxavail_get(mh) + mac_rxrsvd_get(mh) :
38590dc2366fSVenugopal Iyer mac_txavail_get(mh) + mac_txrsvd_get(mh);
38600dc2366fSVenugopal Iyer if (max <= 1) {
38610dc2366fSVenugopal Iyer /*
38620dc2366fSVenugopal Iyer * doesn't support groups or
38630dc2366fSVenugopal Iyer * rings
38640dc2366fSVenugopal Iyer */
38650dc2366fSVenugopal Iyer range->mpr_count = 0;
38660dc2366fSVenugopal Iyer } else {
38670dc2366fSVenugopal Iyer /*
38680dc2366fSVenugopal Iyer * -1 because we have to leave out the
38690dc2366fSVenugopal Iyer * default ring.
38700dc2366fSVenugopal Iyer */
38710dc2366fSVenugopal Iyer _mac_set_range(range, 1, max - 1);
38720dc2366fSVenugopal Iyer }
38730dc2366fSVenugopal Iyer }
38740dc2366fSVenugopal Iyer }
38750dc2366fSVenugopal Iyer return (0);
38760dc2366fSVenugopal Iyer
38770dc2366fSVenugopal Iyer case MAC_PROP_STATUS:
3878dd72704bSRobert Mustacchi case MAC_PROP_MEDIA:
38790dc2366fSVenugopal Iyer if (perm != NULL)
38800dc2366fSVenugopal Iyer *perm = MAC_PROP_PERM_READ;
38810dc2366fSVenugopal Iyer return (0);
38820dc2366fSVenugopal Iyer }
38830dc2366fSVenugopal Iyer
38840dc2366fSVenugopal Iyer /*
38850dc2366fSVenugopal Iyer * Get the property info from the driver if it implements the
38860dc2366fSVenugopal Iyer * property info entry point.
38870dc2366fSVenugopal Iyer */
38880dc2366fSVenugopal Iyer bzero(&state, sizeof (state));
38890dc2366fSVenugopal Iyer
38900dc2366fSVenugopal Iyer if (mip->mi_callbacks->mc_callbacks & MC_PROPINFO) {
38910dc2366fSVenugopal Iyer state.pr_default = default_val;
38920dc2366fSVenugopal Iyer state.pr_default_size = default_size;
38930591ddd0SPrakash Jalan
38940591ddd0SPrakash Jalan /*
38950591ddd0SPrakash Jalan * The caller specifies the maximum number of ranges
38960591ddd0SPrakash Jalan * it can accomodate using mpr_count. We don't touch
38970591ddd0SPrakash Jalan * this value until the driver returns from its
38980591ddd0SPrakash Jalan * mc_propinfo() callback, and ensure we don't exceed
38990591ddd0SPrakash Jalan * this number of range as the driver defines
39000591ddd0SPrakash Jalan * supported range from its mc_propinfo().
39010591ddd0SPrakash Jalan *
39020591ddd0SPrakash Jalan * pr_range_cur_count keeps track of how many ranges
39030591ddd0SPrakash Jalan * were defined by the driver from its mc_propinfo()
39040591ddd0SPrakash Jalan * entry point.
39050591ddd0SPrakash Jalan *
39060591ddd0SPrakash Jalan * On exit, the user-specified range mpr_count returns
39070591ddd0SPrakash Jalan * the number of ranges specified by the driver on
39080591ddd0SPrakash Jalan * success, or the number of ranges it wanted to
39090591ddd0SPrakash Jalan * define if that number of ranges could not be
39100591ddd0SPrakash Jalan * accomodated by the specified range structure. In
39110591ddd0SPrakash Jalan * the latter case, the caller will be able to
39120591ddd0SPrakash Jalan * allocate a larger range structure, and query the
39130591ddd0SPrakash Jalan * property again.
39140591ddd0SPrakash Jalan */
39150591ddd0SPrakash Jalan state.pr_range_cur_count = 0;
39160dc2366fSVenugopal Iyer state.pr_range = range;
39170dc2366fSVenugopal Iyer
39180dc2366fSVenugopal Iyer mip->mi_callbacks->mc_propinfo(mip->mi_driver, name, id,
39190dc2366fSVenugopal Iyer (mac_prop_info_handle_t)&state);
39200dc2366fSVenugopal Iyer
39210591ddd0SPrakash Jalan if (state.pr_flags & MAC_PROP_INFO_RANGE)
39220591ddd0SPrakash Jalan range->mpr_count = state.pr_range_cur_count;
39230591ddd0SPrakash Jalan
39240dc2366fSVenugopal Iyer /*
39250dc2366fSVenugopal Iyer * The operation could fail if the buffer supplied by
39260dc2366fSVenugopal Iyer * the user was too small for the range or default
39270dc2366fSVenugopal Iyer * value of the property.
39280dc2366fSVenugopal Iyer */
39290591ddd0SPrakash Jalan if (state.pr_errno != 0)
39300591ddd0SPrakash Jalan return (state.pr_errno);
39310dc2366fSVenugopal Iyer
39320dc2366fSVenugopal Iyer if (perm != NULL && state.pr_flags & MAC_PROP_INFO_PERM)
39330dc2366fSVenugopal Iyer *perm = state.pr_perm;
39340dc2366fSVenugopal Iyer }
39350dc2366fSVenugopal Iyer
39360dc2366fSVenugopal Iyer /*
39370dc2366fSVenugopal Iyer * The MAC layer may want to provide default values or allowed
39380dc2366fSVenugopal Iyer * ranges for properties if the driver does not provide a
39390dc2366fSVenugopal Iyer * property info entry point, or that entry point exists, but
39400dc2366fSVenugopal Iyer * it did not provide a default value or allowed ranges for
39410dc2366fSVenugopal Iyer * that property.
39420dc2366fSVenugopal Iyer */
39430dc2366fSVenugopal Iyer switch (id) {
39440dc2366fSVenugopal Iyer case MAC_PROP_MTU: {
39450dc2366fSVenugopal Iyer uint32_t sdu;
39460dc2366fSVenugopal Iyer
39471eee170aSErik Nordmark mac_sdu_get2(mh, NULL, &sdu, NULL);
39480dc2366fSVenugopal Iyer
39490dc2366fSVenugopal Iyer if (range != NULL && !(state.pr_flags &
39500dc2366fSVenugopal Iyer MAC_PROP_INFO_RANGE)) {
39510dc2366fSVenugopal Iyer /* MTU range */
39520dc2366fSVenugopal Iyer _mac_set_range(range, sdu, sdu);
39530dc2366fSVenugopal Iyer }
39540dc2366fSVenugopal Iyer
39550dc2366fSVenugopal Iyer if (default_val != NULL && !(state.pr_flags &
39560dc2366fSVenugopal Iyer MAC_PROP_INFO_DEFAULT)) {
39570dc2366fSVenugopal Iyer if (mip->mi_info.mi_media == DL_ETHER)
39580dc2366fSVenugopal Iyer sdu = ETHERMTU;
39590dc2366fSVenugopal Iyer /* default MTU value */
39600dc2366fSVenugopal Iyer bcopy(&sdu, default_val, sizeof (sdu));
39610dc2366fSVenugopal Iyer }
39620dc2366fSVenugopal Iyer }
39630dc2366fSVenugopal Iyer }
39640dc2366fSVenugopal Iyer
39650dc2366fSVenugopal Iyer return (0);
39660dc2366fSVenugopal Iyer }
39670dc2366fSVenugopal Iyer
39685d460eafSCathy Zhou int
mac_fastpath_disable(mac_handle_t mh)39695d460eafSCathy Zhou mac_fastpath_disable(mac_handle_t mh)
39705d460eafSCathy Zhou {
39715d460eafSCathy Zhou mac_impl_t *mip = (mac_impl_t *)mh;
39725d460eafSCathy Zhou
39735d460eafSCathy Zhou if ((mip->mi_state_flags & MIS_LEGACY) == 0)
39745d460eafSCathy Zhou return (0);
39755d460eafSCathy Zhou
39765d460eafSCathy Zhou return (mip->mi_capab_legacy.ml_fastpath_disable(mip->mi_driver));
39775d460eafSCathy Zhou }
39785d460eafSCathy Zhou
39795d460eafSCathy Zhou void
mac_fastpath_enable(mac_handle_t mh)39805d460eafSCathy Zhou mac_fastpath_enable(mac_handle_t mh)
39815d460eafSCathy Zhou {
39825d460eafSCathy Zhou mac_impl_t *mip = (mac_impl_t *)mh;
39835d460eafSCathy Zhou
39845d460eafSCathy Zhou if ((mip->mi_state_flags & MIS_LEGACY) == 0)
39855d460eafSCathy Zhou return;
39865d460eafSCathy Zhou
39875d460eafSCathy Zhou mip->mi_capab_legacy.ml_fastpath_enable(mip->mi_driver);
39885d460eafSCathy Zhou }
39895d460eafSCathy Zhou
3990da14cebeSEric Cheng void
mac_register_priv_prop(mac_impl_t * mip,char ** priv_props)39910dc2366fSVenugopal Iyer mac_register_priv_prop(mac_impl_t *mip, char **priv_props)
39924045d941Ssowmini {
39930dc2366fSVenugopal Iyer uint_t nprops, i;
39944045d941Ssowmini
39950dc2366fSVenugopal Iyer if (priv_props == NULL)
39964045d941Ssowmini return;
39974045d941Ssowmini
39980dc2366fSVenugopal Iyer nprops = 0;
39990dc2366fSVenugopal Iyer while (priv_props[nprops] != NULL)
40000dc2366fSVenugopal Iyer nprops++;
40010dc2366fSVenugopal Iyer if (nprops == 0)
40020dc2366fSVenugopal Iyer return;
40030dc2366fSVenugopal Iyer
40040dc2366fSVenugopal Iyer
40050dc2366fSVenugopal Iyer mip->mi_priv_prop = kmem_zalloc(nprops * sizeof (char *), KM_SLEEP);
40060dc2366fSVenugopal Iyer
40070dc2366fSVenugopal Iyer for (i = 0; i < nprops; i++) {
40080dc2366fSVenugopal Iyer mip->mi_priv_prop[i] = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
40090dc2366fSVenugopal Iyer (void) strlcpy(mip->mi_priv_prop[i], priv_props[i],
40100dc2366fSVenugopal Iyer MAXLINKPROPNAME);
40110dc2366fSVenugopal Iyer }
40120dc2366fSVenugopal Iyer
40130dc2366fSVenugopal Iyer mip->mi_priv_prop_count = nprops;
40144045d941Ssowmini }
40154c3c4458SSowmini Varadhan
4016da14cebeSEric Cheng void
mac_unregister_priv_prop(mac_impl_t * mip)40174c3c4458SSowmini Varadhan mac_unregister_priv_prop(mac_impl_t *mip)
40184c3c4458SSowmini Varadhan {
40190dc2366fSVenugopal Iyer uint_t i;
40204c3c4458SSowmini Varadhan
40210dc2366fSVenugopal Iyer if (mip->mi_priv_prop_count == 0) {
40220dc2366fSVenugopal Iyer ASSERT(mip->mi_priv_prop == NULL);
40230dc2366fSVenugopal Iyer return;
40244c3c4458SSowmini Varadhan }
40250dc2366fSVenugopal Iyer
40260dc2366fSVenugopal Iyer for (i = 0; i < mip->mi_priv_prop_count; i++)
40270dc2366fSVenugopal Iyer kmem_free(mip->mi_priv_prop[i], MAXLINKPROPNAME);
40280dc2366fSVenugopal Iyer kmem_free(mip->mi_priv_prop, mip->mi_priv_prop_count *
40290dc2366fSVenugopal Iyer sizeof (char *));
40300dc2366fSVenugopal Iyer
40310dc2366fSVenugopal Iyer mip->mi_priv_prop = NULL;
40324c3c4458SSowmini Varadhan mip->mi_priv_prop_count = 0;
40334c3c4458SSowmini Varadhan }
4034da14cebeSEric Cheng
4035da14cebeSEric Cheng /*
4036da14cebeSEric Cheng * mac_ring_t 'mr' macros. Some rogue drivers may access ring structure
4037da14cebeSEric Cheng * (by invoking mac_rx()) even after processing mac_stop_ring(). In such
4038da14cebeSEric Cheng * cases if MAC free's the ring structure after mac_stop_ring(), any
4039da14cebeSEric Cheng * illegal access to the ring structure coming from the driver will panic
4040da14cebeSEric Cheng * the system. In order to protect the system from such inadverent access,
4041da14cebeSEric Cheng * we maintain a cache of rings in the mac_impl_t after they get free'd up.
4042da14cebeSEric Cheng * When packets are received on free'd up rings, MAC (through the generation
4043da14cebeSEric Cheng * count mechanism) will drop such packets.
4044da14cebeSEric Cheng */
4045da14cebeSEric Cheng static mac_ring_t *
mac_ring_alloc(mac_impl_t * mip)40460dc2366fSVenugopal Iyer mac_ring_alloc(mac_impl_t *mip)
4047da14cebeSEric Cheng {
4048da14cebeSEric Cheng mac_ring_t *ring;
4049da14cebeSEric Cheng
4050da14cebeSEric Cheng mutex_enter(&mip->mi_ring_lock);
4051da14cebeSEric Cheng if (mip->mi_ring_freelist != NULL) {
4052da14cebeSEric Cheng ring = mip->mi_ring_freelist;
4053da14cebeSEric Cheng mip->mi_ring_freelist = ring->mr_next;
4054da14cebeSEric Cheng bzero(ring, sizeof (mac_ring_t));
4055da14cebeSEric Cheng mutex_exit(&mip->mi_ring_lock);
4056da14cebeSEric Cheng } else {
40570dc2366fSVenugopal Iyer mutex_exit(&mip->mi_ring_lock);
40580dc2366fSVenugopal Iyer ring = kmem_cache_alloc(mac_ring_cache, KM_SLEEP);
4059da14cebeSEric Cheng }
4060da14cebeSEric Cheng ASSERT((ring != NULL) && (ring->mr_state == MR_FREE));
4061da14cebeSEric Cheng return (ring);
4062da14cebeSEric Cheng }
4063da14cebeSEric Cheng
4064da14cebeSEric Cheng static void
mac_ring_free(mac_impl_t * mip,mac_ring_t * ring)4065da14cebeSEric Cheng mac_ring_free(mac_impl_t *mip, mac_ring_t *ring)
4066da14cebeSEric Cheng {
40670dc2366fSVenugopal Iyer ASSERT(ring->mr_state == MR_FREE);
40680dc2366fSVenugopal Iyer
4069da14cebeSEric Cheng mutex_enter(&mip->mi_ring_lock);
4070da14cebeSEric Cheng ring->mr_state = MR_FREE;
4071da14cebeSEric Cheng ring->mr_flag = 0;
4072da14cebeSEric Cheng ring->mr_next = mip->mi_ring_freelist;
40730dc2366fSVenugopal Iyer ring->mr_mip = NULL;
4074da14cebeSEric Cheng mip->mi_ring_freelist = ring;
40750dc2366fSVenugopal Iyer mac_ring_stat_delete(ring);
4076da14cebeSEric Cheng mutex_exit(&mip->mi_ring_lock);
4077da14cebeSEric Cheng }
4078da14cebeSEric Cheng
4079da14cebeSEric Cheng static void
mac_ring_freeall(mac_impl_t * mip)4080da14cebeSEric Cheng mac_ring_freeall(mac_impl_t *mip)
4081da14cebeSEric Cheng {
4082da14cebeSEric Cheng mac_ring_t *ring_next;
4083da14cebeSEric Cheng mutex_enter(&mip->mi_ring_lock);
4084da14cebeSEric Cheng mac_ring_t *ring = mip->mi_ring_freelist;
4085da14cebeSEric Cheng while (ring != NULL) {
4086da14cebeSEric Cheng ring_next = ring->mr_next;
4087da14cebeSEric Cheng kmem_cache_free(mac_ring_cache, ring);
4088da14cebeSEric Cheng ring = ring_next;
4089da14cebeSEric Cheng }
4090da14cebeSEric Cheng mip->mi_ring_freelist = NULL;
4091da14cebeSEric Cheng mutex_exit(&mip->mi_ring_lock);
4092da14cebeSEric Cheng }
4093da14cebeSEric Cheng
4094da14cebeSEric Cheng int
mac_start_ring(mac_ring_t * ring)4095da14cebeSEric Cheng mac_start_ring(mac_ring_t *ring)
4096da14cebeSEric Cheng {
4097da14cebeSEric Cheng int rv = 0;
4098da14cebeSEric Cheng
40990dc2366fSVenugopal Iyer ASSERT(ring->mr_state == MR_FREE);
4100da14cebeSEric Cheng
41010dc2366fSVenugopal Iyer if (ring->mr_start != NULL) {
41020dc2366fSVenugopal Iyer rv = ring->mr_start(ring->mr_driver, ring->mr_gen_num);
41030dc2366fSVenugopal Iyer if (rv != 0)
41040dc2366fSVenugopal Iyer return (rv);
41050dc2366fSVenugopal Iyer }
41060dc2366fSVenugopal Iyer
41070dc2366fSVenugopal Iyer ring->mr_state = MR_INUSE;
4108da14cebeSEric Cheng return (rv);
4109da14cebeSEric Cheng }
4110da14cebeSEric Cheng
4111da14cebeSEric Cheng void
mac_stop_ring(mac_ring_t * ring)4112da14cebeSEric Cheng mac_stop_ring(mac_ring_t *ring)
4113da14cebeSEric Cheng {
41140dc2366fSVenugopal Iyer ASSERT(ring->mr_state == MR_INUSE);
41150dc2366fSVenugopal Iyer
4116da14cebeSEric Cheng if (ring->mr_stop != NULL)
4117da14cebeSEric Cheng ring->mr_stop(ring->mr_driver);
4118da14cebeSEric Cheng
41190dc2366fSVenugopal Iyer ring->mr_state = MR_FREE;
41200dc2366fSVenugopal Iyer
4121da14cebeSEric Cheng /*
4122da14cebeSEric Cheng * Increment the ring generation number for this ring.
4123da14cebeSEric Cheng */
4124da14cebeSEric Cheng ring->mr_gen_num++;
4125da14cebeSEric Cheng }
4126da14cebeSEric Cheng
4127da14cebeSEric Cheng int
mac_start_group(mac_group_t * group)4128da14cebeSEric Cheng mac_start_group(mac_group_t *group)
4129da14cebeSEric Cheng {
4130da14cebeSEric Cheng int rv = 0;
4131da14cebeSEric Cheng
4132da14cebeSEric Cheng if (group->mrg_start != NULL)
4133da14cebeSEric Cheng rv = group->mrg_start(group->mrg_driver);
4134da14cebeSEric Cheng
4135da14cebeSEric Cheng return (rv);
4136da14cebeSEric Cheng }
4137da14cebeSEric Cheng
4138da14cebeSEric Cheng void
mac_stop_group(mac_group_t * group)4139da14cebeSEric Cheng mac_stop_group(mac_group_t *group)
4140da14cebeSEric Cheng {
4141da14cebeSEric Cheng if (group->mrg_stop != NULL)
4142da14cebeSEric Cheng group->mrg_stop(group->mrg_driver);
4143da14cebeSEric Cheng }
4144da14cebeSEric Cheng
4145da14cebeSEric Cheng /*
4146da14cebeSEric Cheng * Called from mac_start() on the default Rx group. Broadcast and multicast
4147da14cebeSEric Cheng * packets are received only on the default group. Hence the default group
4148da14cebeSEric Cheng * needs to be up even if the primary client is not up, for the other groups
4149da14cebeSEric Cheng * to be functional. We do this by calling this function at mac_start time
4150da14cebeSEric Cheng * itself. However the broadcast packets that are received can't make their
4151da14cebeSEric Cheng * way beyond mac_rx until a mac client creates a broadcast flow.
4152da14cebeSEric Cheng */
4153da14cebeSEric Cheng static int
mac_start_group_and_rings(mac_group_t * group)4154da14cebeSEric Cheng mac_start_group_and_rings(mac_group_t *group)
4155da14cebeSEric Cheng {
4156da14cebeSEric Cheng mac_ring_t *ring;
4157da14cebeSEric Cheng int rv = 0;
4158da14cebeSEric Cheng
4159da14cebeSEric Cheng ASSERT(group->mrg_state == MAC_GROUP_STATE_REGISTERED);
4160da14cebeSEric Cheng if ((rv = mac_start_group(group)) != 0)
4161da14cebeSEric Cheng return (rv);
4162da14cebeSEric Cheng
4163da14cebeSEric Cheng for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
4164da14cebeSEric Cheng ASSERT(ring->mr_state == MR_FREE);
416545948e49SRyan Zezeski
4166da14cebeSEric Cheng if ((rv = mac_start_ring(ring)) != 0)
4167da14cebeSEric Cheng goto error;
416845948e49SRyan Zezeski
416945948e49SRyan Zezeski /*
417045948e49SRyan Zezeski * When aggr_set_port_sdu() is called, it will remove
417145948e49SRyan Zezeski * the port client's unicast address. This will cause
417245948e49SRyan Zezeski * MAC to stop the default group's rings on the port
417345948e49SRyan Zezeski * MAC. After it modifies the SDU, it will then re-add
417445948e49SRyan Zezeski * the unicast address. At which time, this function is
417545948e49SRyan Zezeski * called to start the default group's rings. Normally
417645948e49SRyan Zezeski * this function would set the classify type to
417745948e49SRyan Zezeski * MAC_SW_CLASSIFIER; but that will break aggr which
417845948e49SRyan Zezeski * relies on the passthru classify mode being set for
417945948e49SRyan Zezeski * correct delivery (see mac_rx_common()). To avoid
418045948e49SRyan Zezeski * that, we check for a passthru callback and set the
418145948e49SRyan Zezeski * classify type to MAC_PASSTHRU_CLASSIFIER; as it was
418245948e49SRyan Zezeski * before the rings were stopped.
418345948e49SRyan Zezeski */
418445948e49SRyan Zezeski ring->mr_classify_type = (ring->mr_pt_fn != NULL) ?
418545948e49SRyan Zezeski MAC_PASSTHRU_CLASSIFIER : MAC_SW_CLASSIFIER;
4186da14cebeSEric Cheng }
4187da14cebeSEric Cheng return (0);
4188da14cebeSEric Cheng
4189da14cebeSEric Cheng error:
4190da14cebeSEric Cheng mac_stop_group_and_rings(group);
4191da14cebeSEric Cheng return (rv);
4192da14cebeSEric Cheng }
4193da14cebeSEric Cheng
4194da14cebeSEric Cheng /* Called from mac_stop on the default Rx group */
4195da14cebeSEric Cheng static void
mac_stop_group_and_rings(mac_group_t * group)4196da14cebeSEric Cheng mac_stop_group_and_rings(mac_group_t *group)
4197da14cebeSEric Cheng {
4198da14cebeSEric Cheng mac_ring_t *ring;
4199da14cebeSEric Cheng
4200da14cebeSEric Cheng for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
4201da14cebeSEric Cheng if (ring->mr_state != MR_FREE) {
4202da14cebeSEric Cheng mac_stop_ring(ring);
4203da14cebeSEric Cheng ring->mr_flag = 0;
4204da14cebeSEric Cheng ring->mr_classify_type = MAC_NO_CLASSIFIER;
4205da14cebeSEric Cheng }
4206da14cebeSEric Cheng }
4207da14cebeSEric Cheng mac_stop_group(group);
4208da14cebeSEric Cheng }
4209da14cebeSEric Cheng
4210da14cebeSEric Cheng
4211da14cebeSEric Cheng static mac_ring_t *
mac_init_ring(mac_impl_t * mip,mac_group_t * group,int index,mac_capab_rings_t * cap_rings)4212da14cebeSEric Cheng mac_init_ring(mac_impl_t *mip, mac_group_t *group, int index,
4213da14cebeSEric Cheng mac_capab_rings_t *cap_rings)
4214da14cebeSEric Cheng {
42150dc2366fSVenugopal Iyer mac_ring_t *ring, *rnext;
4216da14cebeSEric Cheng mac_ring_info_t ring_info;
42170dc2366fSVenugopal Iyer ddi_intr_handle_t ddi_handle;
4218da14cebeSEric Cheng
42190dc2366fSVenugopal Iyer ring = mac_ring_alloc(mip);
4220da14cebeSEric Cheng
4221da14cebeSEric Cheng /* Prepare basic information of ring */
42220dc2366fSVenugopal Iyer
42230dc2366fSVenugopal Iyer /*
42240dc2366fSVenugopal Iyer * Ring index is numbered to be unique across a particular device.
42250dc2366fSVenugopal Iyer * Ring index computation makes following assumptions:
42260dc2366fSVenugopal Iyer * - For drivers with static grouping (e.g. ixgbe, bge),
42270dc2366fSVenugopal Iyer * ring index exchanged with the driver (e.g. during mr_rget)
42280dc2366fSVenugopal Iyer * is unique only across the group the ring belongs to.
42290dc2366fSVenugopal Iyer * - Drivers with dynamic grouping (e.g. nxge), start
42300dc2366fSVenugopal Iyer * with single group (mrg_index = 0).
42310dc2366fSVenugopal Iyer */
42320dc2366fSVenugopal Iyer ring->mr_index = group->mrg_index * group->mrg_info.mgi_count + index;
4233da14cebeSEric Cheng ring->mr_type = group->mrg_type;
4234da14cebeSEric Cheng ring->mr_gh = (mac_group_handle_t)group;
4235da14cebeSEric Cheng
4236da14cebeSEric Cheng /* Insert the new ring to the list. */
4237da14cebeSEric Cheng ring->mr_next = group->mrg_rings;
4238da14cebeSEric Cheng group->mrg_rings = ring;
4239da14cebeSEric Cheng
4240da14cebeSEric Cheng /* Zero to reuse the info data structure */
4241da14cebeSEric Cheng bzero(&ring_info, sizeof (ring_info));
4242da14cebeSEric Cheng
4243da14cebeSEric Cheng /* Query ring information from driver */
4244da14cebeSEric Cheng cap_rings->mr_rget(mip->mi_driver, group->mrg_type, group->mrg_index,
4245da14cebeSEric Cheng index, &ring_info, (mac_ring_handle_t)ring);
4246da14cebeSEric Cheng
4247da14cebeSEric Cheng ring->mr_info = ring_info;
4248da14cebeSEric Cheng
42490dc2366fSVenugopal Iyer /*
42500dc2366fSVenugopal Iyer * The interrupt handle could be shared among multiple rings.
42510dc2366fSVenugopal Iyer * Thus if there is a bunch of rings that are sharing an
42520dc2366fSVenugopal Iyer * interrupt, then only one ring among the bunch will be made
42530dc2366fSVenugopal Iyer * available for interrupt re-targeting; the rest will have
42540dc2366fSVenugopal Iyer * ddi_shared flag set to TRUE and would not be available for
42550dc2366fSVenugopal Iyer * be interrupt re-targeting.
42560dc2366fSVenugopal Iyer */
42570dc2366fSVenugopal Iyer if ((ddi_handle = ring_info.mri_intr.mi_ddi_handle) != NULL) {
42580dc2366fSVenugopal Iyer rnext = ring->mr_next;
42590dc2366fSVenugopal Iyer while (rnext != NULL) {
42600dc2366fSVenugopal Iyer if (rnext->mr_info.mri_intr.mi_ddi_handle ==
42610dc2366fSVenugopal Iyer ddi_handle) {
42620dc2366fSVenugopal Iyer /*
42630dc2366fSVenugopal Iyer * If default ring (mr_index == 0) is part
42640dc2366fSVenugopal Iyer * of a group of rings sharing an
42650dc2366fSVenugopal Iyer * interrupt, then set ddi_shared flag for
42660dc2366fSVenugopal Iyer * the default ring and give another ring
42670dc2366fSVenugopal Iyer * the chance to be re-targeted.
42680dc2366fSVenugopal Iyer */
42690dc2366fSVenugopal Iyer if (rnext->mr_index == 0 &&
42700dc2366fSVenugopal Iyer !rnext->mr_info.mri_intr.mi_ddi_shared) {
42710dc2366fSVenugopal Iyer rnext->mr_info.mri_intr.mi_ddi_shared =
42720dc2366fSVenugopal Iyer B_TRUE;
42730dc2366fSVenugopal Iyer } else {
42740dc2366fSVenugopal Iyer ring->mr_info.mri_intr.mi_ddi_shared =
42750dc2366fSVenugopal Iyer B_TRUE;
42760dc2366fSVenugopal Iyer }
42770dc2366fSVenugopal Iyer break;
42780dc2366fSVenugopal Iyer }
42790dc2366fSVenugopal Iyer rnext = rnext->mr_next;
42800dc2366fSVenugopal Iyer }
42810dc2366fSVenugopal Iyer /*
42820dc2366fSVenugopal Iyer * If rnext is NULL, then no matching ddi_handle was found.
42830dc2366fSVenugopal Iyer * Rx rings get registered first. So if this is a Tx ring,
42840dc2366fSVenugopal Iyer * then go through all the Rx rings and see if there is a
42850dc2366fSVenugopal Iyer * matching ddi handle.
42860dc2366fSVenugopal Iyer */
42870dc2366fSVenugopal Iyer if (rnext == NULL && ring->mr_type == MAC_RING_TYPE_TX) {
42880dc2366fSVenugopal Iyer mac_compare_ddi_handle(mip->mi_rx_groups,
42890dc2366fSVenugopal Iyer mip->mi_rx_group_count, ring);
42900dc2366fSVenugopal Iyer }
42910dc2366fSVenugopal Iyer }
42920dc2366fSVenugopal Iyer
4293da14cebeSEric Cheng /* Update ring's status */
4294da14cebeSEric Cheng ring->mr_state = MR_FREE;
4295da14cebeSEric Cheng ring->mr_flag = 0;
4296da14cebeSEric Cheng
4297da14cebeSEric Cheng /* Update the ring count of the group */
4298da14cebeSEric Cheng group->mrg_cur_count++;
42990dc2366fSVenugopal Iyer
43000dc2366fSVenugopal Iyer /* Create per ring kstats */
43010dc2366fSVenugopal Iyer if (ring->mr_stat != NULL) {
43020dc2366fSVenugopal Iyer ring->mr_mip = mip;
43030dc2366fSVenugopal Iyer mac_ring_stat_create(ring);
43040dc2366fSVenugopal Iyer }
43050dc2366fSVenugopal Iyer
4306da14cebeSEric Cheng return (ring);
4307da14cebeSEric Cheng }
4308da14cebeSEric Cheng
4309da14cebeSEric Cheng /*
4310da14cebeSEric Cheng * Rings are chained together for easy regrouping.
4311da14cebeSEric Cheng */
4312da14cebeSEric Cheng static void
mac_init_group(mac_impl_t * mip,mac_group_t * group,int size,mac_capab_rings_t * cap_rings)4313da14cebeSEric Cheng mac_init_group(mac_impl_t *mip, mac_group_t *group, int size,
4314da14cebeSEric Cheng mac_capab_rings_t *cap_rings)
4315da14cebeSEric Cheng {
4316da14cebeSEric Cheng int index;
4317da14cebeSEric Cheng
4318da14cebeSEric Cheng /*
4319da14cebeSEric Cheng * Initialize all ring members of this group. Size of zero will not
4320da14cebeSEric Cheng * enter the loop, so it's safe for initializing an empty group.
4321da14cebeSEric Cheng */
4322da14cebeSEric Cheng for (index = size - 1; index >= 0; index--)
4323da14cebeSEric Cheng (void) mac_init_ring(mip, group, index, cap_rings);
4324da14cebeSEric Cheng }
4325da14cebeSEric Cheng
4326da14cebeSEric Cheng int
mac_init_rings(mac_impl_t * mip,mac_ring_type_t rtype)4327da14cebeSEric Cheng mac_init_rings(mac_impl_t *mip, mac_ring_type_t rtype)
4328da14cebeSEric Cheng {
4329da14cebeSEric Cheng mac_capab_rings_t *cap_rings;
43300dc2366fSVenugopal Iyer mac_group_t *group;
43310dc2366fSVenugopal Iyer mac_group_t *groups;
4332da14cebeSEric Cheng mac_group_info_t group_info;
4333da14cebeSEric Cheng uint_t group_free = 0;
4334da14cebeSEric Cheng uint_t ring_left;
4335da14cebeSEric Cheng mac_ring_t *ring;
43360dc2366fSVenugopal Iyer int g;
43370dc2366fSVenugopal Iyer int err = 0;
43380dc2366fSVenugopal Iyer uint_t grpcnt;
43390dc2366fSVenugopal Iyer boolean_t pseudo_txgrp = B_FALSE;
4340da14cebeSEric Cheng
4341da14cebeSEric Cheng switch (rtype) {
4342da14cebeSEric Cheng case MAC_RING_TYPE_RX:
4343da14cebeSEric Cheng ASSERT(mip->mi_rx_groups == NULL);
4344da14cebeSEric Cheng
4345da14cebeSEric Cheng cap_rings = &mip->mi_rx_rings_cap;
4346da14cebeSEric Cheng cap_rings->mr_type = MAC_RING_TYPE_RX;
4347da14cebeSEric Cheng break;
4348da14cebeSEric Cheng case MAC_RING_TYPE_TX:
4349da14cebeSEric Cheng ASSERT(mip->mi_tx_groups == NULL);
4350da14cebeSEric Cheng
4351da14cebeSEric Cheng cap_rings = &mip->mi_tx_rings_cap;
4352da14cebeSEric Cheng cap_rings->mr_type = MAC_RING_TYPE_TX;
4353da14cebeSEric Cheng break;
4354da14cebeSEric Cheng default:
4355da14cebeSEric Cheng ASSERT(B_FALSE);
4356da14cebeSEric Cheng }
4357da14cebeSEric Cheng
43580dc2366fSVenugopal Iyer if (!i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_RINGS, cap_rings))
4359da14cebeSEric Cheng return (0);
43600dc2366fSVenugopal Iyer grpcnt = cap_rings->mr_gnum;
43610dc2366fSVenugopal Iyer
43620dc2366fSVenugopal Iyer /*
43630dc2366fSVenugopal Iyer * If we have multiple TX rings, but only one TX group, we can
43640dc2366fSVenugopal Iyer * create pseudo TX groups (one per TX ring) in the MAC layer,
43650dc2366fSVenugopal Iyer * except for an aggr. For an aggr currently we maintain only
43660dc2366fSVenugopal Iyer * one group with all the rings (for all its ports), going
43670dc2366fSVenugopal Iyer * forwards we might change this.
43680dc2366fSVenugopal Iyer */
43690dc2366fSVenugopal Iyer if (rtype == MAC_RING_TYPE_TX &&
43700dc2366fSVenugopal Iyer cap_rings->mr_gnum == 0 && cap_rings->mr_rnum > 0 &&
43710dc2366fSVenugopal Iyer (mip->mi_state_flags & MIS_IS_AGGR) == 0) {
43720dc2366fSVenugopal Iyer /*
43730dc2366fSVenugopal Iyer * The -1 here is because we create a default TX group
43740dc2366fSVenugopal Iyer * with all the rings in it.
43750dc2366fSVenugopal Iyer */
43760dc2366fSVenugopal Iyer grpcnt = cap_rings->mr_rnum - 1;
43770dc2366fSVenugopal Iyer pseudo_txgrp = B_TRUE;
43780dc2366fSVenugopal Iyer }
4379da14cebeSEric Cheng
4380da14cebeSEric Cheng /*
4381da14cebeSEric Cheng * Allocate a contiguous buffer for all groups.
4382da14cebeSEric Cheng */
43830dc2366fSVenugopal Iyer groups = kmem_zalloc(sizeof (mac_group_t) * (grpcnt+ 1), KM_SLEEP);
4384da14cebeSEric Cheng
4385da14cebeSEric Cheng ring_left = cap_rings->mr_rnum;
4386da14cebeSEric Cheng
4387da14cebeSEric Cheng /*
4388da14cebeSEric Cheng * Get all ring groups if any, and get their ring members
4389da14cebeSEric Cheng * if any.
4390da14cebeSEric Cheng */
43910dc2366fSVenugopal Iyer for (g = 0; g < grpcnt; g++) {
4392da14cebeSEric Cheng group = groups + g;
4393da14cebeSEric Cheng
4394da14cebeSEric Cheng /* Prepare basic information of the group */
4395da14cebeSEric Cheng group->mrg_index = g;
4396da14cebeSEric Cheng group->mrg_type = rtype;
4397da14cebeSEric Cheng group->mrg_state = MAC_GROUP_STATE_UNINIT;
4398da14cebeSEric Cheng group->mrg_mh = (mac_handle_t)mip;
4399da14cebeSEric Cheng group->mrg_next = group + 1;
4400da14cebeSEric Cheng
4401da14cebeSEric Cheng /* Zero to reuse the info data structure */
4402da14cebeSEric Cheng bzero(&group_info, sizeof (group_info));
4403da14cebeSEric Cheng
44040dc2366fSVenugopal Iyer if (pseudo_txgrp) {
44050dc2366fSVenugopal Iyer /*
44060dc2366fSVenugopal Iyer * This is a pseudo group that we created, apart
44070dc2366fSVenugopal Iyer * from setting the state there is nothing to be
44080dc2366fSVenugopal Iyer * done.
44090dc2366fSVenugopal Iyer */
44100dc2366fSVenugopal Iyer group->mrg_state = MAC_GROUP_STATE_REGISTERED;
44110dc2366fSVenugopal Iyer group_free++;
44120dc2366fSVenugopal Iyer continue;
44130dc2366fSVenugopal Iyer }
4414da14cebeSEric Cheng /* Query group information from driver */
4415da14cebeSEric Cheng cap_rings->mr_gget(mip->mi_driver, rtype, g, &group_info,
4416da14cebeSEric Cheng (mac_group_handle_t)group);
4417da14cebeSEric Cheng
4418da14cebeSEric Cheng switch (cap_rings->mr_group_type) {
4419da14cebeSEric Cheng case MAC_GROUP_TYPE_DYNAMIC:
4420da14cebeSEric Cheng if (cap_rings->mr_gaddring == NULL ||
4421da14cebeSEric Cheng cap_rings->mr_gremring == NULL) {
4422da14cebeSEric Cheng DTRACE_PROBE3(
4423da14cebeSEric Cheng mac__init__rings_no_addremring,
4424da14cebeSEric Cheng char *, mip->mi_name,
4425da14cebeSEric Cheng mac_group_add_ring_t,
4426da14cebeSEric Cheng cap_rings->mr_gaddring,
4427da14cebeSEric Cheng mac_group_add_ring_t,
4428da14cebeSEric Cheng cap_rings->mr_gremring);
4429da14cebeSEric Cheng err = EINVAL;
4430da14cebeSEric Cheng goto bail;
4431da14cebeSEric Cheng }
4432da14cebeSEric Cheng
4433da14cebeSEric Cheng switch (rtype) {
4434da14cebeSEric Cheng case MAC_RING_TYPE_RX:
4435da14cebeSEric Cheng /*
4436da14cebeSEric Cheng * The first RX group must have non-zero
4437da14cebeSEric Cheng * rings, and the following groups must
4438da14cebeSEric Cheng * have zero rings.
4439da14cebeSEric Cheng */
4440da14cebeSEric Cheng if (g == 0 && group_info.mgi_count == 0) {
4441da14cebeSEric Cheng DTRACE_PROBE1(
4442da14cebeSEric Cheng mac__init__rings__rx__def__zero,
4443da14cebeSEric Cheng char *, mip->mi_name);
4444da14cebeSEric Cheng err = EINVAL;
4445da14cebeSEric Cheng goto bail;
4446da14cebeSEric Cheng }
4447da14cebeSEric Cheng if (g > 0 && group_info.mgi_count != 0) {
4448da14cebeSEric Cheng DTRACE_PROBE3(
4449da14cebeSEric Cheng mac__init__rings__rx__nonzero,
4450da14cebeSEric Cheng char *, mip->mi_name,
4451da14cebeSEric Cheng int, g, int, group_info.mgi_count);
4452da14cebeSEric Cheng err = EINVAL;
4453da14cebeSEric Cheng goto bail;
4454da14cebeSEric Cheng }
4455da14cebeSEric Cheng break;
4456da14cebeSEric Cheng case MAC_RING_TYPE_TX:
4457da14cebeSEric Cheng /*
4458da14cebeSEric Cheng * All TX ring groups must have zero rings.
4459da14cebeSEric Cheng */
4460da14cebeSEric Cheng if (group_info.mgi_count != 0) {
4461da14cebeSEric Cheng DTRACE_PROBE3(
4462da14cebeSEric Cheng mac__init__rings__tx__nonzero,
4463da14cebeSEric Cheng char *, mip->mi_name,
4464da14cebeSEric Cheng int, g, int, group_info.mgi_count);
4465da14cebeSEric Cheng err = EINVAL;
4466da14cebeSEric Cheng goto bail;
4467da14cebeSEric Cheng }
4468da14cebeSEric Cheng break;
4469da14cebeSEric Cheng }
4470da14cebeSEric Cheng break;
4471da14cebeSEric Cheng case MAC_GROUP_TYPE_STATIC:
4472da14cebeSEric Cheng /*
4473da14cebeSEric Cheng * Note that an empty group is allowed, e.g., an aggr
4474da14cebeSEric Cheng * would start with an empty group.
4475da14cebeSEric Cheng */
4476da14cebeSEric Cheng break;
4477da14cebeSEric Cheng default:
4478da14cebeSEric Cheng /* unknown group type */
4479da14cebeSEric Cheng DTRACE_PROBE2(mac__init__rings__unknown__type,
4480da14cebeSEric Cheng char *, mip->mi_name,
4481da14cebeSEric Cheng int, cap_rings->mr_group_type);
4482da14cebeSEric Cheng err = EINVAL;
4483da14cebeSEric Cheng goto bail;
4484da14cebeSEric Cheng }
4485da14cebeSEric Cheng
4486da14cebeSEric Cheng
4487da14cebeSEric Cheng /*
448884de666eSRyan Zezeski * The driver must register some form of hardware MAC
448984de666eSRyan Zezeski * filter in order for Rx groups to support multiple
449084de666eSRyan Zezeski * MAC addresses.
4491da14cebeSEric Cheng */
4492d05c2e38SDan McDonald if (rtype == MAC_RING_TYPE_RX &&
449384de666eSRyan Zezeski (group_info.mgi_addmac == NULL ||
449484de666eSRyan Zezeski group_info.mgi_remmac == NULL)) {
449584de666eSRyan Zezeski DTRACE_PROBE1(mac__init__rings__no__mac__filter,
449684de666eSRyan Zezeski char *, mip->mi_name);
4497d05c2e38SDan McDonald err = EINVAL;
4498da14cebeSEric Cheng goto bail;
4499da14cebeSEric Cheng }
4500da14cebeSEric Cheng
4501da14cebeSEric Cheng /* Cache driver-supplied information */
4502da14cebeSEric Cheng group->mrg_info = group_info;
4503da14cebeSEric Cheng
4504da14cebeSEric Cheng /* Update the group's status and group count. */
45050dc2366fSVenugopal Iyer mac_set_group_state(group, MAC_GROUP_STATE_REGISTERED);
4506da14cebeSEric Cheng group_free++;
4507da14cebeSEric Cheng
4508da14cebeSEric Cheng group->mrg_rings = NULL;
4509da14cebeSEric Cheng group->mrg_cur_count = 0;
4510da14cebeSEric Cheng mac_init_group(mip, group, group_info.mgi_count, cap_rings);
4511da14cebeSEric Cheng ring_left -= group_info.mgi_count;
4512da14cebeSEric Cheng
4513da14cebeSEric Cheng /* The current group size should be equal to default value */
4514da14cebeSEric Cheng ASSERT(group->mrg_cur_count == group_info.mgi_count);
4515da14cebeSEric Cheng }
4516da14cebeSEric Cheng
4517da14cebeSEric Cheng /* Build up a dummy group for free resources as a pool */
45180dc2366fSVenugopal Iyer group = groups + grpcnt;
4519da14cebeSEric Cheng
4520da14cebeSEric Cheng /* Prepare basic information of the group */
4521da14cebeSEric Cheng group->mrg_index = -1;
4522da14cebeSEric Cheng group->mrg_type = rtype;
4523da14cebeSEric Cheng group->mrg_state = MAC_GROUP_STATE_UNINIT;
4524da14cebeSEric Cheng group->mrg_mh = (mac_handle_t)mip;
4525da14cebeSEric Cheng group->mrg_next = NULL;
4526da14cebeSEric Cheng
4527da14cebeSEric Cheng /*
4528da14cebeSEric Cheng * If there are ungrouped rings, allocate a continuous buffer for
4529da14cebeSEric Cheng * remaining resources.
4530da14cebeSEric Cheng */
4531da14cebeSEric Cheng if (ring_left != 0) {
4532da14cebeSEric Cheng group->mrg_rings = NULL;
4533da14cebeSEric Cheng group->mrg_cur_count = 0;
4534da14cebeSEric Cheng mac_init_group(mip, group, ring_left, cap_rings);
4535da14cebeSEric Cheng
4536da14cebeSEric Cheng /* The current group size should be equal to ring_left */
4537da14cebeSEric Cheng ASSERT(group->mrg_cur_count == ring_left);
4538da14cebeSEric Cheng
4539da14cebeSEric Cheng ring_left = 0;
4540da14cebeSEric Cheng
4541da14cebeSEric Cheng /* Update this group's status */
45420dc2366fSVenugopal Iyer mac_set_group_state(group, MAC_GROUP_STATE_REGISTERED);
454384de666eSRyan Zezeski } else {
4544da14cebeSEric Cheng group->mrg_rings = NULL;
454584de666eSRyan Zezeski }
4546da14cebeSEric Cheng
4547da14cebeSEric Cheng ASSERT(ring_left == 0);
4548da14cebeSEric Cheng
4549da14cebeSEric Cheng bail:
45500dc2366fSVenugopal Iyer
4551da14cebeSEric Cheng /* Cache other important information to finalize the initialization */
4552da14cebeSEric Cheng switch (rtype) {
4553da14cebeSEric Cheng case MAC_RING_TYPE_RX:
4554da14cebeSEric Cheng mip->mi_rx_group_type = cap_rings->mr_group_type;
4555da14cebeSEric Cheng mip->mi_rx_group_count = cap_rings->mr_gnum;
4556da14cebeSEric Cheng mip->mi_rx_groups = groups;
45570dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = groups;
45580dc2366fSVenugopal Iyer if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
45590dc2366fSVenugopal Iyer /*
45600dc2366fSVenugopal Iyer * The default ring is reserved since it is
45610dc2366fSVenugopal Iyer * used for sending the broadcast etc. packets.
45620dc2366fSVenugopal Iyer */
45630dc2366fSVenugopal Iyer mip->mi_rxrings_avail =
45640dc2366fSVenugopal Iyer mip->mi_rx_groups->mrg_cur_count - 1;
45650dc2366fSVenugopal Iyer mip->mi_rxrings_rsvd = 1;
45660dc2366fSVenugopal Iyer }
45670dc2366fSVenugopal Iyer /*
45680dc2366fSVenugopal Iyer * The default group cannot be reserved. It is used by
45690dc2366fSVenugopal Iyer * all the clients that do not have an exclusive group.
45700dc2366fSVenugopal Iyer */
45710dc2366fSVenugopal Iyer mip->mi_rxhwclnt_avail = mip->mi_rx_group_count - 1;
45720dc2366fSVenugopal Iyer mip->mi_rxhwclnt_used = 1;
4573da14cebeSEric Cheng break;
4574da14cebeSEric Cheng case MAC_RING_TYPE_TX:
45750dc2366fSVenugopal Iyer mip->mi_tx_group_type = pseudo_txgrp ? MAC_GROUP_TYPE_DYNAMIC :
45760dc2366fSVenugopal Iyer cap_rings->mr_group_type;
45770dc2366fSVenugopal Iyer mip->mi_tx_group_count = grpcnt;
4578da14cebeSEric Cheng mip->mi_tx_group_free = group_free;
4579da14cebeSEric Cheng mip->mi_tx_groups = groups;
4580da14cebeSEric Cheng
45810dc2366fSVenugopal Iyer group = groups + grpcnt;
4582da14cebeSEric Cheng ring = group->mrg_rings;
45830dc2366fSVenugopal Iyer /*
45840dc2366fSVenugopal Iyer * The ring can be NULL in the case of aggr. Aggr will
45850dc2366fSVenugopal Iyer * have an empty Tx group which will get populated
45860dc2366fSVenugopal Iyer * later when pseudo Tx rings are added after
45870dc2366fSVenugopal Iyer * mac_register() is done.
45880dc2366fSVenugopal Iyer */
45890dc2366fSVenugopal Iyer if (ring == NULL) {
45900dc2366fSVenugopal Iyer ASSERT(mip->mi_state_flags & MIS_IS_AGGR);
45910dc2366fSVenugopal Iyer /*
45920dc2366fSVenugopal Iyer * pass the group to aggr so it can add Tx
45930dc2366fSVenugopal Iyer * rings to the group later.
45940dc2366fSVenugopal Iyer */
45950dc2366fSVenugopal Iyer cap_rings->mr_gget(mip->mi_driver, rtype, 0, NULL,
45960dc2366fSVenugopal Iyer (mac_group_handle_t)group);
45970dc2366fSVenugopal Iyer /*
45980dc2366fSVenugopal Iyer * Even though there are no rings at this time
45990dc2366fSVenugopal Iyer * (rings will come later), set the group
46000dc2366fSVenugopal Iyer * state to registered.
46010dc2366fSVenugopal Iyer */
46020dc2366fSVenugopal Iyer group->mrg_state = MAC_GROUP_STATE_REGISTERED;
46030dc2366fSVenugopal Iyer } else {
46040dc2366fSVenugopal Iyer /*
46050dc2366fSVenugopal Iyer * Ring 0 is used as the default one and it could be
46060dc2366fSVenugopal Iyer * assigned to a client as well.
46070dc2366fSVenugopal Iyer */
4608da14cebeSEric Cheng while ((ring->mr_index != 0) && (ring->mr_next != NULL))
4609da14cebeSEric Cheng ring = ring->mr_next;
4610da14cebeSEric Cheng ASSERT(ring->mr_index == 0);
4611da14cebeSEric Cheng mip->mi_default_tx_ring = (mac_ring_handle_t)ring;
46120dc2366fSVenugopal Iyer }
4613af5d3c33SToomas Soome if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
46140dc2366fSVenugopal Iyer mip->mi_txrings_avail = group->mrg_cur_count - 1;
46150dc2366fSVenugopal Iyer /*
46160dc2366fSVenugopal Iyer * The default ring cannot be reserved.
46170dc2366fSVenugopal Iyer */
46180dc2366fSVenugopal Iyer mip->mi_txrings_rsvd = 1;
4619af5d3c33SToomas Soome }
46200dc2366fSVenugopal Iyer /*
46210dc2366fSVenugopal Iyer * The default group cannot be reserved. It will be shared
46220dc2366fSVenugopal Iyer * by clients that do not have an exclusive group.
46230dc2366fSVenugopal Iyer */
46240dc2366fSVenugopal Iyer mip->mi_txhwclnt_avail = mip->mi_tx_group_count;
46250dc2366fSVenugopal Iyer mip->mi_txhwclnt_used = 1;
4626da14cebeSEric Cheng break;
4627da14cebeSEric Cheng default:
4628da14cebeSEric Cheng ASSERT(B_FALSE);
4629da14cebeSEric Cheng }
4630da14cebeSEric Cheng
4631da14cebeSEric Cheng if (err != 0)
4632da14cebeSEric Cheng mac_free_rings(mip, rtype);
4633da14cebeSEric Cheng
4634da14cebeSEric Cheng return (err);
4635da14cebeSEric Cheng }
4636da14cebeSEric Cheng
4637da14cebeSEric Cheng /*
46380dc2366fSVenugopal Iyer * The ddi interrupt handle could be shared amoung rings. If so, compare
46390dc2366fSVenugopal Iyer * the new ring's ddi handle with the existing ones and set ddi_shared
46400dc2366fSVenugopal Iyer * flag.
46410dc2366fSVenugopal Iyer */
46420dc2366fSVenugopal Iyer void
mac_compare_ddi_handle(mac_group_t * groups,uint_t grpcnt,mac_ring_t * cring)46430dc2366fSVenugopal Iyer mac_compare_ddi_handle(mac_group_t *groups, uint_t grpcnt, mac_ring_t *cring)
46440dc2366fSVenugopal Iyer {
46450dc2366fSVenugopal Iyer mac_group_t *group;
46460dc2366fSVenugopal Iyer mac_ring_t *ring;
46470dc2366fSVenugopal Iyer ddi_intr_handle_t ddi_handle;
46480dc2366fSVenugopal Iyer int g;
46490dc2366fSVenugopal Iyer
46500dc2366fSVenugopal Iyer ddi_handle = cring->mr_info.mri_intr.mi_ddi_handle;
46510dc2366fSVenugopal Iyer for (g = 0; g < grpcnt; g++) {
46520dc2366fSVenugopal Iyer group = groups + g;
46530dc2366fSVenugopal Iyer for (ring = group->mrg_rings; ring != NULL;
46540dc2366fSVenugopal Iyer ring = ring->mr_next) {
46550dc2366fSVenugopal Iyer if (ring == cring)
46560dc2366fSVenugopal Iyer continue;
46570dc2366fSVenugopal Iyer if (ring->mr_info.mri_intr.mi_ddi_handle ==
46580dc2366fSVenugopal Iyer ddi_handle) {
46590dc2366fSVenugopal Iyer if (cring->mr_type == MAC_RING_TYPE_RX &&
46600dc2366fSVenugopal Iyer ring->mr_index == 0 &&
46610dc2366fSVenugopal Iyer !ring->mr_info.mri_intr.mi_ddi_shared) {
46620dc2366fSVenugopal Iyer ring->mr_info.mri_intr.mi_ddi_shared =
46630dc2366fSVenugopal Iyer B_TRUE;
46640dc2366fSVenugopal Iyer } else {
46650dc2366fSVenugopal Iyer cring->mr_info.mri_intr.mi_ddi_shared =
46660dc2366fSVenugopal Iyer B_TRUE;
46670dc2366fSVenugopal Iyer }
46680dc2366fSVenugopal Iyer return;
46690dc2366fSVenugopal Iyer }
46700dc2366fSVenugopal Iyer }
46710dc2366fSVenugopal Iyer }
46720dc2366fSVenugopal Iyer }
46730dc2366fSVenugopal Iyer
46740dc2366fSVenugopal Iyer /*
46750dc2366fSVenugopal Iyer * Called to free all groups of particular type (RX or TX). It's assumed that
46760dc2366fSVenugopal Iyer * no clients are using these groups.
4677da14cebeSEric Cheng */
4678da14cebeSEric Cheng void
mac_free_rings(mac_impl_t * mip,mac_ring_type_t rtype)4679da14cebeSEric Cheng mac_free_rings(mac_impl_t *mip, mac_ring_type_t rtype)
4680da14cebeSEric Cheng {
4681da14cebeSEric Cheng mac_group_t *group, *groups;
4682da14cebeSEric Cheng uint_t group_count;
4683da14cebeSEric Cheng
4684da14cebeSEric Cheng switch (rtype) {
4685da14cebeSEric Cheng case MAC_RING_TYPE_RX:
4686da14cebeSEric Cheng if (mip->mi_rx_groups == NULL)
4687da14cebeSEric Cheng return;
4688da14cebeSEric Cheng
4689da14cebeSEric Cheng groups = mip->mi_rx_groups;
4690da14cebeSEric Cheng group_count = mip->mi_rx_group_count;
4691da14cebeSEric Cheng
4692da14cebeSEric Cheng mip->mi_rx_groups = NULL;
46930dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = NULL;
4694da14cebeSEric Cheng mip->mi_rx_group_count = 0;
4695da14cebeSEric Cheng break;
4696da14cebeSEric Cheng case MAC_RING_TYPE_TX:
4697da14cebeSEric Cheng ASSERT(mip->mi_tx_group_count == mip->mi_tx_group_free);
4698da14cebeSEric Cheng
4699da14cebeSEric Cheng if (mip->mi_tx_groups == NULL)
4700da14cebeSEric Cheng return;
4701da14cebeSEric Cheng
4702da14cebeSEric Cheng groups = mip->mi_tx_groups;
4703da14cebeSEric Cheng group_count = mip->mi_tx_group_count;
4704da14cebeSEric Cheng
4705da14cebeSEric Cheng mip->mi_tx_groups = NULL;
4706da14cebeSEric Cheng mip->mi_tx_group_count = 0;
4707da14cebeSEric Cheng mip->mi_tx_group_free = 0;
4708da14cebeSEric Cheng mip->mi_default_tx_ring = NULL;
4709da14cebeSEric Cheng break;
4710da14cebeSEric Cheng default:
4711da14cebeSEric Cheng ASSERT(B_FALSE);
4712da14cebeSEric Cheng }
4713da14cebeSEric Cheng
4714da14cebeSEric Cheng for (group = groups; group != NULL; group = group->mrg_next) {
4715da14cebeSEric Cheng mac_ring_t *ring;
4716da14cebeSEric Cheng
4717da14cebeSEric Cheng if (group->mrg_cur_count == 0)
4718da14cebeSEric Cheng continue;
4719da14cebeSEric Cheng
4720da14cebeSEric Cheng ASSERT(group->mrg_rings != NULL);
4721da14cebeSEric Cheng
4722da14cebeSEric Cheng while ((ring = group->mrg_rings) != NULL) {
4723da14cebeSEric Cheng group->mrg_rings = ring->mr_next;
4724da14cebeSEric Cheng mac_ring_free(mip, ring);
4725da14cebeSEric Cheng }
4726da14cebeSEric Cheng }
4727da14cebeSEric Cheng
4728da14cebeSEric Cheng /* Free all the cached rings */
4729da14cebeSEric Cheng mac_ring_freeall(mip);
4730da14cebeSEric Cheng /* Free the block of group data strutures */
4731da14cebeSEric Cheng kmem_free(groups, sizeof (mac_group_t) * (group_count + 1));
4732da14cebeSEric Cheng }
4733da14cebeSEric Cheng
4734da14cebeSEric Cheng /*
473584de666eSRyan Zezeski * Associate the VLAN filter to the receive group.
473684de666eSRyan Zezeski */
473784de666eSRyan Zezeski int
mac_group_addvlan(mac_group_t * group,uint16_t vlan)473884de666eSRyan Zezeski mac_group_addvlan(mac_group_t *group, uint16_t vlan)
473984de666eSRyan Zezeski {
474084de666eSRyan Zezeski VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
474184de666eSRyan Zezeski VERIFY3P(group->mrg_info.mgi_addvlan, !=, NULL);
474284de666eSRyan Zezeski
474384de666eSRyan Zezeski if (vlan > VLAN_ID_MAX)
474484de666eSRyan Zezeski return (EINVAL);
474584de666eSRyan Zezeski
474684de666eSRyan Zezeski vlan = MAC_VLAN_UNTAGGED_VID(vlan);
474784de666eSRyan Zezeski return (group->mrg_info.mgi_addvlan(group->mrg_info.mgi_driver, vlan));
474884de666eSRyan Zezeski }
474984de666eSRyan Zezeski
475084de666eSRyan Zezeski /*
475184de666eSRyan Zezeski * Dissociate the VLAN from the receive group.
475284de666eSRyan Zezeski */
475384de666eSRyan Zezeski int
mac_group_remvlan(mac_group_t * group,uint16_t vlan)475484de666eSRyan Zezeski mac_group_remvlan(mac_group_t *group, uint16_t vlan)
475584de666eSRyan Zezeski {
475684de666eSRyan Zezeski VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
475784de666eSRyan Zezeski VERIFY3P(group->mrg_info.mgi_remvlan, !=, NULL);
475884de666eSRyan Zezeski
475984de666eSRyan Zezeski if (vlan > VLAN_ID_MAX)
476084de666eSRyan Zezeski return (EINVAL);
476184de666eSRyan Zezeski
476284de666eSRyan Zezeski vlan = MAC_VLAN_UNTAGGED_VID(vlan);
476384de666eSRyan Zezeski return (group->mrg_info.mgi_remvlan(group->mrg_info.mgi_driver, vlan));
476484de666eSRyan Zezeski }
476584de666eSRyan Zezeski
476684de666eSRyan Zezeski /*
4767da14cebeSEric Cheng * Associate a MAC address with a receive group.
4768da14cebeSEric Cheng *
4769da14cebeSEric Cheng * The return value of this function should always be checked properly, because
4770da14cebeSEric Cheng * any type of failure could cause unexpected results. A group can be added
4771da14cebeSEric Cheng * or removed with a MAC address only after it has been reserved. Ideally,
4772da14cebeSEric Cheng * a successful reservation always leads to calling mac_group_addmac() to
4773da14cebeSEric Cheng * steer desired traffic. Failure of adding an unicast MAC address doesn't
4774da14cebeSEric Cheng * always imply that the group is functioning abnormally.
4775da14cebeSEric Cheng *
4776da14cebeSEric Cheng * Currently this function is called everywhere, and it reflects assumptions
4777da14cebeSEric Cheng * about MAC addresses in the implementation. CR 6735196.
4778da14cebeSEric Cheng */
4779da14cebeSEric Cheng int
mac_group_addmac(mac_group_t * group,const uint8_t * addr)4780da14cebeSEric Cheng mac_group_addmac(mac_group_t *group, const uint8_t *addr)
4781da14cebeSEric Cheng {
478284de666eSRyan Zezeski VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
478384de666eSRyan Zezeski VERIFY3P(group->mrg_info.mgi_addmac, !=, NULL);
4784da14cebeSEric Cheng
4785da14cebeSEric Cheng return (group->mrg_info.mgi_addmac(group->mrg_info.mgi_driver, addr));
4786da14cebeSEric Cheng }
4787da14cebeSEric Cheng
4788da14cebeSEric Cheng /*
4789da14cebeSEric Cheng * Remove the association between MAC address and receive group.
4790da14cebeSEric Cheng */
4791da14cebeSEric Cheng int
mac_group_remmac(mac_group_t * group,const uint8_t * addr)4792da14cebeSEric Cheng mac_group_remmac(mac_group_t *group, const uint8_t *addr)
4793da14cebeSEric Cheng {
479484de666eSRyan Zezeski VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
479584de666eSRyan Zezeski VERIFY3P(group->mrg_info.mgi_remmac, !=, NULL);
4796da14cebeSEric Cheng
4797da14cebeSEric Cheng return (group->mrg_info.mgi_remmac(group->mrg_info.mgi_driver, addr));
4798da14cebeSEric Cheng }
4799da14cebeSEric Cheng
4800da14cebeSEric Cheng /*
4801c61a1653SRyan Zezeski * This is the entry point for packets transmitted through the bridge
4802c61a1653SRyan Zezeski * code. If no bridge is in place, mac_ring_tx() transmits via the tx
4803c61a1653SRyan Zezeski * ring. The 'rh' pointer may be NULL to select the default ring.
48044eaa4710SRishi Srivatsavai */
48054eaa4710SRishi Srivatsavai mblk_t *
mac_bridge_tx(mac_impl_t * mip,mac_ring_handle_t rh,mblk_t * mp)48064eaa4710SRishi Srivatsavai mac_bridge_tx(mac_impl_t *mip, mac_ring_handle_t rh, mblk_t *mp)
48074eaa4710SRishi Srivatsavai {
48084eaa4710SRishi Srivatsavai mac_handle_t mh;
48094eaa4710SRishi Srivatsavai
48104eaa4710SRishi Srivatsavai /*
48114eaa4710SRishi Srivatsavai * Once we take a reference on the bridge link, the bridge
48124eaa4710SRishi Srivatsavai * module itself can't unload, so the callback pointers are
48134eaa4710SRishi Srivatsavai * stable.
48144eaa4710SRishi Srivatsavai */
48154eaa4710SRishi Srivatsavai mutex_enter(&mip->mi_bridge_lock);
48164eaa4710SRishi Srivatsavai if ((mh = mip->mi_bridge_link) != NULL)
48174eaa4710SRishi Srivatsavai mac_bridge_ref_cb(mh, B_TRUE);
48184eaa4710SRishi Srivatsavai mutex_exit(&mip->mi_bridge_lock);
48194eaa4710SRishi Srivatsavai if (mh == NULL) {
4820c61a1653SRyan Zezeski mp = mac_ring_tx((mac_handle_t)mip, rh, mp);
48214eaa4710SRishi Srivatsavai } else {
4822c61a1653SRyan Zezeski /*
4823c61a1653SRyan Zezeski * The bridge may place this mblk on a provider's Tx
4824c61a1653SRyan Zezeski * path, a mac's Rx path, or both. Since we don't have
4825c61a1653SRyan Zezeski * enough information at this point, we can't be sure
4826c61a1653SRyan Zezeski * that the destination(s) are capable of handling the
4827c61a1653SRyan Zezeski * hardware offloads requested by the mblk. We emulate
4828c61a1653SRyan Zezeski * them here as it is the safest choice. In the
4829c61a1653SRyan Zezeski * future, if bridge performance becomes a priority,
4830c61a1653SRyan Zezeski * we can elide the emulation here and leave the
4831c61a1653SRyan Zezeski * choice up to bridge.
4832c61a1653SRyan Zezeski *
4833c61a1653SRyan Zezeski * We don't clear the DB_CKSUMFLAGS here because
4834c61a1653SRyan Zezeski * HCK_IPV4_HDRCKSUM (Tx) and HCK_IPV4_HDRCKSUM_OK
4835c61a1653SRyan Zezeski * (Rx) still have the same value. If the bridge
4836c61a1653SRyan Zezeski * receives a packet from a HCKSUM_IPHDRCKSUM NIC then
4837c61a1653SRyan Zezeski * the mac(s) it is forwarded on may calculate the
4838c61a1653SRyan Zezeski * checksum again, but incorrectly (because the
4839c61a1653SRyan Zezeski * checksum field is not zero). Until the
4840c61a1653SRyan Zezeski * HCK_IPV4_HDRCKSUM/HCK_IPV4_HDRCKSUM_OK issue is
4841c61a1653SRyan Zezeski * resovled, we leave the flag clearing in bridge
4842c61a1653SRyan Zezeski * itself.
4843c61a1653SRyan Zezeski */
4844c61a1653SRyan Zezeski if ((DB_CKSUMFLAGS(mp) & (HCK_TX_FLAGS | HW_LSO_FLAGS)) != 0) {
4845c61a1653SRyan Zezeski mac_hw_emul(&mp, NULL, NULL, MAC_ALL_EMULS);
4846c61a1653SRyan Zezeski }
4847c61a1653SRyan Zezeski
48484eaa4710SRishi Srivatsavai mp = mac_bridge_tx_cb(mh, rh, mp);
48494eaa4710SRishi Srivatsavai mac_bridge_ref_cb(mh, B_FALSE);
48504eaa4710SRishi Srivatsavai }
48514eaa4710SRishi Srivatsavai
48524eaa4710SRishi Srivatsavai return (mp);
48534eaa4710SRishi Srivatsavai }
48544eaa4710SRishi Srivatsavai
48554eaa4710SRishi Srivatsavai /*
4856da14cebeSEric Cheng * Find a ring from its index.
4857da14cebeSEric Cheng */
48580dc2366fSVenugopal Iyer mac_ring_handle_t
mac_find_ring(mac_group_handle_t gh,int index)48590dc2366fSVenugopal Iyer mac_find_ring(mac_group_handle_t gh, int index)
4860da14cebeSEric Cheng {
48610dc2366fSVenugopal Iyer mac_group_t *group = (mac_group_t *)gh;
4862da14cebeSEric Cheng mac_ring_t *ring = group->mrg_rings;
4863da14cebeSEric Cheng
4864da14cebeSEric Cheng for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next)
4865da14cebeSEric Cheng if (ring->mr_index == index)
4866da14cebeSEric Cheng break;
4867da14cebeSEric Cheng
48680dc2366fSVenugopal Iyer return ((mac_ring_handle_t)ring);
4869da14cebeSEric Cheng }
4870da14cebeSEric Cheng /*
4871da14cebeSEric Cheng * Add a ring to an existing group.
4872da14cebeSEric Cheng *
4873da14cebeSEric Cheng * The ring must be either passed directly (for example if the ring
4874da14cebeSEric Cheng * movement is initiated by the framework), or specified through a driver
4875da14cebeSEric Cheng * index (for example when the ring is added by the driver.
4876da14cebeSEric Cheng *
4877da14cebeSEric Cheng * The caller needs to call mac_perim_enter() before calling this function.
4878da14cebeSEric Cheng */
4879da14cebeSEric Cheng int
i_mac_group_add_ring(mac_group_t * group,mac_ring_t * ring,int index)4880da14cebeSEric Cheng i_mac_group_add_ring(mac_group_t *group, mac_ring_t *ring, int index)
4881da14cebeSEric Cheng {
4882da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
4883da14cebeSEric Cheng mac_capab_rings_t *cap_rings;
4884da14cebeSEric Cheng boolean_t driver_call = (ring == NULL);
4885da14cebeSEric Cheng mac_group_type_t group_type;
4886da14cebeSEric Cheng int ret = 0;
48870dc2366fSVenugopal Iyer flow_entry_t *flent;
4888da14cebeSEric Cheng
4889da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4890da14cebeSEric Cheng
4891da14cebeSEric Cheng switch (group->mrg_type) {
4892da14cebeSEric Cheng case MAC_RING_TYPE_RX:
4893da14cebeSEric Cheng cap_rings = &mip->mi_rx_rings_cap;
4894da14cebeSEric Cheng group_type = mip->mi_rx_group_type;
4895da14cebeSEric Cheng break;
4896da14cebeSEric Cheng case MAC_RING_TYPE_TX:
4897da14cebeSEric Cheng cap_rings = &mip->mi_tx_rings_cap;
4898da14cebeSEric Cheng group_type = mip->mi_tx_group_type;
4899da14cebeSEric Cheng break;
4900da14cebeSEric Cheng default:
4901da14cebeSEric Cheng ASSERT(B_FALSE);
4902da14cebeSEric Cheng }
4903da14cebeSEric Cheng
4904da14cebeSEric Cheng /*
4905da14cebeSEric Cheng * There should be no ring with the same ring index in the target
4906da14cebeSEric Cheng * group.
4907da14cebeSEric Cheng */
49080dc2366fSVenugopal Iyer ASSERT(mac_find_ring((mac_group_handle_t)group,
49090dc2366fSVenugopal Iyer driver_call ? index : ring->mr_index) == NULL);
4910da14cebeSEric Cheng
4911da14cebeSEric Cheng if (driver_call) {
4912da14cebeSEric Cheng /*
4913da14cebeSEric Cheng * The function is called as a result of a request from
4914da14cebeSEric Cheng * a driver to add a ring to an existing group, for example
4915da14cebeSEric Cheng * from the aggregation driver. Allocate a new mac_ring_t
4916da14cebeSEric Cheng * for that ring.
4917da14cebeSEric Cheng */
4918da14cebeSEric Cheng ring = mac_init_ring(mip, group, index, cap_rings);
4919da14cebeSEric Cheng ASSERT(group->mrg_state > MAC_GROUP_STATE_UNINIT);
4920da14cebeSEric Cheng } else {
4921da14cebeSEric Cheng /*
4922da14cebeSEric Cheng * The function is called as a result of a MAC layer request
4923da14cebeSEric Cheng * to add a ring to an existing group. In this case the
4924da14cebeSEric Cheng * ring is being moved between groups, which requires
4925da14cebeSEric Cheng * the underlying driver to support dynamic grouping,
4926da14cebeSEric Cheng * and the mac_ring_t already exists.
4927da14cebeSEric Cheng */
4928da14cebeSEric Cheng ASSERT(group_type == MAC_GROUP_TYPE_DYNAMIC);
49290dc2366fSVenugopal Iyer ASSERT(group->mrg_driver == NULL ||
49300dc2366fSVenugopal Iyer cap_rings->mr_gaddring != NULL);
4931da14cebeSEric Cheng ASSERT(ring->mr_gh == NULL);
4932da14cebeSEric Cheng }
4933da14cebeSEric Cheng
4934da14cebeSEric Cheng /*
4935da14cebeSEric Cheng * At this point the ring should not be in use, and it should be
4936da14cebeSEric Cheng * of the right for the target group.
4937da14cebeSEric Cheng */
4938da14cebeSEric Cheng ASSERT(ring->mr_state < MR_INUSE);
4939da14cebeSEric Cheng ASSERT(ring->mr_srs == NULL);
4940da14cebeSEric Cheng ASSERT(ring->mr_type == group->mrg_type);
4941da14cebeSEric Cheng
4942da14cebeSEric Cheng if (!driver_call) {
4943da14cebeSEric Cheng /*
4944da14cebeSEric Cheng * Add the driver level hardware ring if the process was not
4945da14cebeSEric Cheng * initiated by the driver, and the target group is not the
4946da14cebeSEric Cheng * group.
4947da14cebeSEric Cheng */
4948da14cebeSEric Cheng if (group->mrg_driver != NULL) {
4949da14cebeSEric Cheng cap_rings->mr_gaddring(group->mrg_driver,
4950da14cebeSEric Cheng ring->mr_driver, ring->mr_type);
4951da14cebeSEric Cheng }
4952da14cebeSEric Cheng
4953da14cebeSEric Cheng /*
4954da14cebeSEric Cheng * Insert the ring ahead existing rings.
4955da14cebeSEric Cheng */
4956da14cebeSEric Cheng ring->mr_next = group->mrg_rings;
4957da14cebeSEric Cheng group->mrg_rings = ring;
4958da14cebeSEric Cheng ring->mr_gh = (mac_group_handle_t)group;
4959da14cebeSEric Cheng group->mrg_cur_count++;
4960da14cebeSEric Cheng }
4961da14cebeSEric Cheng
4962da14cebeSEric Cheng /*
4963da14cebeSEric Cheng * If the group has not been actively used, we're done.
4964da14cebeSEric Cheng */
4965da14cebeSEric Cheng if (group->mrg_index != -1 &&
4966da14cebeSEric Cheng group->mrg_state < MAC_GROUP_STATE_RESERVED)
4967da14cebeSEric Cheng return (0);
4968da14cebeSEric Cheng
4969da14cebeSEric Cheng /*
4970da14cebeSEric Cheng * Start the ring if needed. Failure causes to undo the grouping action.
4971da14cebeSEric Cheng */
49720dc2366fSVenugopal Iyer if (ring->mr_state != MR_INUSE) {
4973da14cebeSEric Cheng if ((ret = mac_start_ring(ring)) != 0) {
4974da14cebeSEric Cheng if (!driver_call) {
4975da14cebeSEric Cheng cap_rings->mr_gremring(group->mrg_driver,
4976da14cebeSEric Cheng ring->mr_driver, ring->mr_type);
4977da14cebeSEric Cheng }
4978da14cebeSEric Cheng group->mrg_cur_count--;
4979da14cebeSEric Cheng group->mrg_rings = ring->mr_next;
4980da14cebeSEric Cheng
4981da14cebeSEric Cheng ring->mr_gh = NULL;
4982da14cebeSEric Cheng
4983da14cebeSEric Cheng if (driver_call)
4984da14cebeSEric Cheng mac_ring_free(mip, ring);
4985da14cebeSEric Cheng
4986da14cebeSEric Cheng return (ret);
4987da14cebeSEric Cheng }
49880dc2366fSVenugopal Iyer }
4989da14cebeSEric Cheng
4990da14cebeSEric Cheng /*
49910dc2366fSVenugopal Iyer * Set up SRS/SR according to the ring type.
4992da14cebeSEric Cheng */
49930dc2366fSVenugopal Iyer switch (ring->mr_type) {
49940dc2366fSVenugopal Iyer case MAC_RING_TYPE_RX:
49950dc2366fSVenugopal Iyer /*
499684de666eSRyan Zezeski * Setup an SRS on top of the new ring if the group is
499784de666eSRyan Zezeski * reserved for someone's exclusive use.
49980dc2366fSVenugopal Iyer */
49990dc2366fSVenugopal Iyer if (group->mrg_state == MAC_GROUP_STATE_RESERVED) {
500084de666eSRyan Zezeski mac_client_impl_t *mcip = MAC_GROUP_ONLY_CLIENT(group);
50010dc2366fSVenugopal Iyer
500284de666eSRyan Zezeski VERIFY3P(mcip, !=, NULL);
50030dc2366fSVenugopal Iyer flent = mcip->mci_flent;
500484de666eSRyan Zezeski VERIFY3S(flent->fe_rx_srs_cnt, >, 0);
50050dc2366fSVenugopal Iyer mac_rx_srs_group_setup(mcip, flent, SRST_LINK);
500684de666eSRyan Zezeski mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
500784de666eSRyan Zezeski mac_rx_deliver, mcip, NULL, NULL);
50080dc2366fSVenugopal Iyer } else {
50090dc2366fSVenugopal Iyer ring->mr_classify_type = MAC_SW_CLASSIFIER;
50100dc2366fSVenugopal Iyer }
50110dc2366fSVenugopal Iyer break;
50120dc2366fSVenugopal Iyer case MAC_RING_TYPE_TX:
50130dc2366fSVenugopal Iyer {
50140dc2366fSVenugopal Iyer mac_grp_client_t *mgcp = group->mrg_clients;
50150dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
50160dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
50170dc2366fSVenugopal Iyer mac_srs_tx_t *tx;
50180dc2366fSVenugopal Iyer
50190dc2366fSVenugopal Iyer if (MAC_GROUP_NO_CLIENT(group)) {
50200dc2366fSVenugopal Iyer if (ring->mr_state == MR_INUSE)
50210dc2366fSVenugopal Iyer mac_stop_ring(ring);
50220dc2366fSVenugopal Iyer ring->mr_flag = 0;
50230dc2366fSVenugopal Iyer break;
50240dc2366fSVenugopal Iyer }
50250dc2366fSVenugopal Iyer /*
50260dc2366fSVenugopal Iyer * If the rings are being moved to a group that has
50270dc2366fSVenugopal Iyer * clients using it, then add the new rings to the
50280dc2366fSVenugopal Iyer * clients SRS.
50290dc2366fSVenugopal Iyer */
50300dc2366fSVenugopal Iyer while (mgcp != NULL) {
50310dc2366fSVenugopal Iyer boolean_t is_aggr;
50320dc2366fSVenugopal Iyer
50330dc2366fSVenugopal Iyer mcip = mgcp->mgc_client;
50340dc2366fSVenugopal Iyer flent = mcip->mci_flent;
503584de666eSRyan Zezeski is_aggr = (mcip->mci_state_flags & MCIS_IS_AGGR_CLIENT);
50360dc2366fSVenugopal Iyer mac_srs = MCIP_TX_SRS(mcip);
50370dc2366fSVenugopal Iyer tx = &mac_srs->srs_tx;
50380dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
50390dc2366fSVenugopal Iyer /*
50400dc2366fSVenugopal Iyer * If we are growing from 1 to multiple rings.
50410dc2366fSVenugopal Iyer */
50420dc2366fSVenugopal Iyer if (tx->st_mode == SRS_TX_BW ||
50430dc2366fSVenugopal Iyer tx->st_mode == SRS_TX_SERIALIZE ||
50440dc2366fSVenugopal Iyer tx->st_mode == SRS_TX_DEFAULT) {
50450dc2366fSVenugopal Iyer mac_ring_t *tx_ring = tx->st_arg2;
50460dc2366fSVenugopal Iyer
50470dc2366fSVenugopal Iyer tx->st_arg2 = NULL;
50480dc2366fSVenugopal Iyer mac_tx_srs_stat_recreate(mac_srs, B_TRUE);
50490dc2366fSVenugopal Iyer mac_tx_srs_add_ring(mac_srs, tx_ring);
50500dc2366fSVenugopal Iyer if (mac_srs->srs_type & SRST_BW_CONTROL) {
50510dc2366fSVenugopal Iyer tx->st_mode = is_aggr ? SRS_TX_BW_AGGR :
50520dc2366fSVenugopal Iyer SRS_TX_BW_FANOUT;
50530dc2366fSVenugopal Iyer } else {
50540dc2366fSVenugopal Iyer tx->st_mode = is_aggr ? SRS_TX_AGGR :
50550dc2366fSVenugopal Iyer SRS_TX_FANOUT;
50560dc2366fSVenugopal Iyer }
50570dc2366fSVenugopal Iyer tx->st_func = mac_tx_get_func(tx->st_mode);
50580dc2366fSVenugopal Iyer }
50590dc2366fSVenugopal Iyer mac_tx_srs_add_ring(mac_srs, ring);
50600dc2366fSVenugopal Iyer mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
50610dc2366fSVenugopal Iyer mac_rx_deliver, mcip, NULL, NULL);
50620dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
50630dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
50640dc2366fSVenugopal Iyer }
50650dc2366fSVenugopal Iyer break;
50660dc2366fSVenugopal Iyer }
50670dc2366fSVenugopal Iyer default:
50680dc2366fSVenugopal Iyer ASSERT(B_FALSE);
50690dc2366fSVenugopal Iyer }
50700dc2366fSVenugopal Iyer /*
50710dc2366fSVenugopal Iyer * For aggr, the default ring will be NULL to begin with. If it
50720dc2366fSVenugopal Iyer * is NULL, then pick the first ring that gets added as the
50730dc2366fSVenugopal Iyer * default ring. Any ring in an aggregation can be removed at
50740dc2366fSVenugopal Iyer * any time (by the user action of removing a link) and if the
50750dc2366fSVenugopal Iyer * current default ring gets removed, then a new one gets
50760dc2366fSVenugopal Iyer * picked (see i_mac_group_rem_ring()).
50770dc2366fSVenugopal Iyer */
50780dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_AGGR &&
50790dc2366fSVenugopal Iyer mip->mi_default_tx_ring == NULL &&
50800dc2366fSVenugopal Iyer ring->mr_type == MAC_RING_TYPE_TX) {
50810dc2366fSVenugopal Iyer mip->mi_default_tx_ring = (mac_ring_handle_t)ring;
50820dc2366fSVenugopal Iyer }
50830dc2366fSVenugopal Iyer
5084da14cebeSEric Cheng MAC_RING_UNMARK(ring, MR_INCIPIENT);
5085da14cebeSEric Cheng return (0);
5086da14cebeSEric Cheng }
5087da14cebeSEric Cheng
5088da14cebeSEric Cheng /*
5089da14cebeSEric Cheng * Remove a ring from it's current group. MAC internal function for dynamic
5090da14cebeSEric Cheng * grouping.
5091da14cebeSEric Cheng *
5092da14cebeSEric Cheng * The caller needs to call mac_perim_enter() before calling this function.
5093da14cebeSEric Cheng */
5094da14cebeSEric Cheng void
i_mac_group_rem_ring(mac_group_t * group,mac_ring_t * ring,boolean_t driver_call)5095da14cebeSEric Cheng i_mac_group_rem_ring(mac_group_t *group, mac_ring_t *ring,
5096da14cebeSEric Cheng boolean_t driver_call)
5097da14cebeSEric Cheng {
5098da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
5099da14cebeSEric Cheng mac_capab_rings_t *cap_rings = NULL;
5100da14cebeSEric Cheng mac_group_type_t group_type;
5101da14cebeSEric Cheng
5102da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5103da14cebeSEric Cheng
51040dc2366fSVenugopal Iyer ASSERT(mac_find_ring((mac_group_handle_t)group,
51050dc2366fSVenugopal Iyer ring->mr_index) == (mac_ring_handle_t)ring);
5106da14cebeSEric Cheng ASSERT((mac_group_t *)ring->mr_gh == group);
5107da14cebeSEric Cheng ASSERT(ring->mr_type == group->mrg_type);
5108da14cebeSEric Cheng
51090dc2366fSVenugopal Iyer if (ring->mr_state == MR_INUSE)
51100dc2366fSVenugopal Iyer mac_stop_ring(ring);
5111da14cebeSEric Cheng switch (ring->mr_type) {
5112da14cebeSEric Cheng case MAC_RING_TYPE_RX:
5113da14cebeSEric Cheng group_type = mip->mi_rx_group_type;
5114da14cebeSEric Cheng cap_rings = &mip->mi_rx_rings_cap;
5115da14cebeSEric Cheng
5116da14cebeSEric Cheng /*
5117da14cebeSEric Cheng * Only hardware classified packets hold a reference to the
5118da14cebeSEric Cheng * ring all the way up the Rx path. mac_rx_srs_remove()
5119da14cebeSEric Cheng * will take care of quiescing the Rx path and removing the
5120da14cebeSEric Cheng * SRS. The software classified path neither holds a reference
5121da14cebeSEric Cheng * nor any association with the ring in mac_rx.
5122da14cebeSEric Cheng */
5123da14cebeSEric Cheng if (ring->mr_srs != NULL) {
5124da14cebeSEric Cheng mac_rx_srs_remove(ring->mr_srs);
5125da14cebeSEric Cheng ring->mr_srs = NULL;
5126da14cebeSEric Cheng }
5127da14cebeSEric Cheng
5128da14cebeSEric Cheng break;
5129da14cebeSEric Cheng case MAC_RING_TYPE_TX:
51300dc2366fSVenugopal Iyer {
51310dc2366fSVenugopal Iyer mac_grp_client_t *mgcp;
51320dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
51330dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
51340dc2366fSVenugopal Iyer mac_srs_tx_t *tx;
51350dc2366fSVenugopal Iyer mac_ring_t *rem_ring;
51360dc2366fSVenugopal Iyer mac_group_t *defgrp;
51370dc2366fSVenugopal Iyer uint_t ring_info = 0;
51380dc2366fSVenugopal Iyer
5139da14cebeSEric Cheng /*
51400dc2366fSVenugopal Iyer * For TX this function is invoked in three
5141da14cebeSEric Cheng * cases:
5142da14cebeSEric Cheng *
5143da14cebeSEric Cheng * 1) In the case of a failure during the
5144da14cebeSEric Cheng * initial creation of a group when a share is
5145da14cebeSEric Cheng * associated with a MAC client. So the SRS is not
5146da14cebeSEric Cheng * yet setup, and will be setup later after the
5147da14cebeSEric Cheng * group has been reserved and populated.
5148da14cebeSEric Cheng *
5149da14cebeSEric Cheng * 2) From mac_release_tx_group() when freeing
5150da14cebeSEric Cheng * a TX SRS.
5151da14cebeSEric Cheng *
51520dc2366fSVenugopal Iyer * 3) In the case of aggr, when a port gets removed,
51530dc2366fSVenugopal Iyer * the pseudo Tx rings that it exposed gets removed.
51540dc2366fSVenugopal Iyer *
51550dc2366fSVenugopal Iyer * In the first two cases the SRS and its soft
51560dc2366fSVenugopal Iyer * rings are already quiesced.
5157da14cebeSEric Cheng */
51580dc2366fSVenugopal Iyer if (driver_call) {
51590dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
51600dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
51610dc2366fSVenugopal Iyer mac_soft_ring_t *sringp;
51620dc2366fSVenugopal Iyer mac_srs_tx_t *srs_tx;
51630dc2366fSVenugopal Iyer
51640dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_AGGR &&
51650dc2366fSVenugopal Iyer mip->mi_default_tx_ring ==
51660dc2366fSVenugopal Iyer (mac_ring_handle_t)ring) {
51670dc2366fSVenugopal Iyer /* pick a new default Tx ring */
51680dc2366fSVenugopal Iyer mip->mi_default_tx_ring =
51690dc2366fSVenugopal Iyer (group->mrg_rings != ring) ?
51700dc2366fSVenugopal Iyer (mac_ring_handle_t)group->mrg_rings :
51710dc2366fSVenugopal Iyer (mac_ring_handle_t)(ring->mr_next);
51720dc2366fSVenugopal Iyer }
51730dc2366fSVenugopal Iyer /* Presently only aggr case comes here */
51740dc2366fSVenugopal Iyer if (group->mrg_state != MAC_GROUP_STATE_RESERVED)
51750dc2366fSVenugopal Iyer break;
51760dc2366fSVenugopal Iyer
51770dc2366fSVenugopal Iyer mcip = MAC_GROUP_ONLY_CLIENT(group);
51780dc2366fSVenugopal Iyer ASSERT(mcip != NULL);
517984de666eSRyan Zezeski ASSERT(mcip->mci_state_flags & MCIS_IS_AGGR_CLIENT);
51800dc2366fSVenugopal Iyer mac_srs = MCIP_TX_SRS(mcip);
51810dc2366fSVenugopal Iyer ASSERT(mac_srs->srs_tx.st_mode == SRS_TX_AGGR ||
51820dc2366fSVenugopal Iyer mac_srs->srs_tx.st_mode == SRS_TX_BW_AGGR);
51830dc2366fSVenugopal Iyer srs_tx = &mac_srs->srs_tx;
51840dc2366fSVenugopal Iyer /*
51850dc2366fSVenugopal Iyer * Wakeup any callers blocked on this
51860dc2366fSVenugopal Iyer * Tx ring due to flow control.
51870dc2366fSVenugopal Iyer */
51880dc2366fSVenugopal Iyer sringp = srs_tx->st_soft_rings[ring->mr_index];
51890dc2366fSVenugopal Iyer ASSERT(sringp != NULL);
51900dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip, (mac_tx_cookie_t)sringp);
51910dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
51920dc2366fSVenugopal Iyer mac_tx_srs_del_ring(mac_srs, ring);
51930dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
51940dc2366fSVenugopal Iyer break;
51950dc2366fSVenugopal Iyer }
51960dc2366fSVenugopal Iyer ASSERT(ring != (mac_ring_t *)mip->mi_default_tx_ring);
5197da14cebeSEric Cheng group_type = mip->mi_tx_group_type;
5198da14cebeSEric Cheng cap_rings = &mip->mi_tx_rings_cap;
51990dc2366fSVenugopal Iyer /*
52000dc2366fSVenugopal Iyer * See if we need to take it out of the MAC clients using
52010dc2366fSVenugopal Iyer * this group
52020dc2366fSVenugopal Iyer */
52030dc2366fSVenugopal Iyer if (MAC_GROUP_NO_CLIENT(group))
5204da14cebeSEric Cheng break;
52050dc2366fSVenugopal Iyer mgcp = group->mrg_clients;
52060dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
52070dc2366fSVenugopal Iyer while (mgcp != NULL) {
52080dc2366fSVenugopal Iyer mcip = mgcp->mgc_client;
52090dc2366fSVenugopal Iyer mac_srs = MCIP_TX_SRS(mcip);
52100dc2366fSVenugopal Iyer tx = &mac_srs->srs_tx;
52110dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
52120dc2366fSVenugopal Iyer /*
52130dc2366fSVenugopal Iyer * If we are here when removing rings from the
52140dc2366fSVenugopal Iyer * defgroup, mac_reserve_tx_ring would have
52150dc2366fSVenugopal Iyer * already deleted the ring from the MAC
52160dc2366fSVenugopal Iyer * clients in the group.
52170dc2366fSVenugopal Iyer */
52180dc2366fSVenugopal Iyer if (group != defgrp) {
52190dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip,
52200dc2366fSVenugopal Iyer (mac_tx_cookie_t)
52210dc2366fSVenugopal Iyer mac_tx_srs_get_soft_ring(mac_srs, ring));
52220dc2366fSVenugopal Iyer mac_tx_srs_del_ring(mac_srs, ring);
52230dc2366fSVenugopal Iyer }
52240dc2366fSVenugopal Iyer /*
52250dc2366fSVenugopal Iyer * Additionally, if we are left with only
52260dc2366fSVenugopal Iyer * one ring in the group after this, we need
52270dc2366fSVenugopal Iyer * to modify the mode etc. to. (We haven't
52280dc2366fSVenugopal Iyer * yet taken the ring out, so we check with 2).
52290dc2366fSVenugopal Iyer */
52300dc2366fSVenugopal Iyer if (group->mrg_cur_count == 2) {
52310dc2366fSVenugopal Iyer if (ring->mr_next == NULL)
52320dc2366fSVenugopal Iyer rem_ring = group->mrg_rings;
52330dc2366fSVenugopal Iyer else
52340dc2366fSVenugopal Iyer rem_ring = ring->mr_next;
52350dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip,
52360dc2366fSVenugopal Iyer (mac_tx_cookie_t)
52370dc2366fSVenugopal Iyer mac_tx_srs_get_soft_ring(mac_srs,
52380dc2366fSVenugopal Iyer rem_ring));
52390dc2366fSVenugopal Iyer mac_tx_srs_del_ring(mac_srs, rem_ring);
52400dc2366fSVenugopal Iyer if (rem_ring->mr_state != MR_INUSE) {
52410dc2366fSVenugopal Iyer (void) mac_start_ring(rem_ring);
52420dc2366fSVenugopal Iyer }
52430dc2366fSVenugopal Iyer tx->st_arg2 = (void *)rem_ring;
52440dc2366fSVenugopal Iyer mac_tx_srs_stat_recreate(mac_srs, B_FALSE);
52450dc2366fSVenugopal Iyer ring_info = mac_hwring_getinfo(
52460dc2366fSVenugopal Iyer (mac_ring_handle_t)rem_ring);
52470dc2366fSVenugopal Iyer /*
52480dc2366fSVenugopal Iyer * We are shrinking from multiple
52490dc2366fSVenugopal Iyer * to 1 ring.
52500dc2366fSVenugopal Iyer */
52510dc2366fSVenugopal Iyer if (mac_srs->srs_type & SRST_BW_CONTROL) {
52520dc2366fSVenugopal Iyer tx->st_mode = SRS_TX_BW;
52530dc2366fSVenugopal Iyer } else if (mac_tx_serialize ||
52540dc2366fSVenugopal Iyer (ring_info & MAC_RING_TX_SERIALIZE)) {
52550dc2366fSVenugopal Iyer tx->st_mode = SRS_TX_SERIALIZE;
52560dc2366fSVenugopal Iyer } else {
52570dc2366fSVenugopal Iyer tx->st_mode = SRS_TX_DEFAULT;
52580dc2366fSVenugopal Iyer }
52590dc2366fSVenugopal Iyer tx->st_func = mac_tx_get_func(tx->st_mode);
52600dc2366fSVenugopal Iyer }
52610dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
52620dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
52630dc2366fSVenugopal Iyer }
52640dc2366fSVenugopal Iyer break;
52650dc2366fSVenugopal Iyer }
5266da14cebeSEric Cheng default:
5267da14cebeSEric Cheng ASSERT(B_FALSE);
5268da14cebeSEric Cheng }
5269da14cebeSEric Cheng
5270da14cebeSEric Cheng /*
5271da14cebeSEric Cheng * Remove the ring from the group.
5272da14cebeSEric Cheng */
5273da14cebeSEric Cheng if (ring == group->mrg_rings)
5274da14cebeSEric Cheng group->mrg_rings = ring->mr_next;
5275da14cebeSEric Cheng else {
5276da14cebeSEric Cheng mac_ring_t *pre;
5277da14cebeSEric Cheng
5278da14cebeSEric Cheng pre = group->mrg_rings;
5279da14cebeSEric Cheng while (pre->mr_next != ring)
5280da14cebeSEric Cheng pre = pre->mr_next;
5281da14cebeSEric Cheng pre->mr_next = ring->mr_next;
5282da14cebeSEric Cheng }
5283da14cebeSEric Cheng group->mrg_cur_count--;
5284da14cebeSEric Cheng
5285da14cebeSEric Cheng if (!driver_call) {
5286da14cebeSEric Cheng ASSERT(group_type == MAC_GROUP_TYPE_DYNAMIC);
52870dc2366fSVenugopal Iyer ASSERT(group->mrg_driver == NULL ||
52880dc2366fSVenugopal Iyer cap_rings->mr_gremring != NULL);
5289da14cebeSEric Cheng
5290da14cebeSEric Cheng /*
5291da14cebeSEric Cheng * Remove the driver level hardware ring.
5292da14cebeSEric Cheng */
5293da14cebeSEric Cheng if (group->mrg_driver != NULL) {
5294da14cebeSEric Cheng cap_rings->mr_gremring(group->mrg_driver,
5295da14cebeSEric Cheng ring->mr_driver, ring->mr_type);
5296da14cebeSEric Cheng }
5297da14cebeSEric Cheng }
5298da14cebeSEric Cheng
5299da14cebeSEric Cheng ring->mr_gh = NULL;
53000dc2366fSVenugopal Iyer if (driver_call)
5301da14cebeSEric Cheng mac_ring_free(mip, ring);
53020dc2366fSVenugopal Iyer else
5303da14cebeSEric Cheng ring->mr_flag = 0;
5304da14cebeSEric Cheng }
5305da14cebeSEric Cheng
5306da14cebeSEric Cheng /*
5307da14cebeSEric Cheng * Move a ring to the target group. If needed, remove the ring from the group
5308da14cebeSEric Cheng * that it currently belongs to.
5309da14cebeSEric Cheng *
5310da14cebeSEric Cheng * The caller need to enter MAC's perimeter by calling mac_perim_enter().
5311da14cebeSEric Cheng */
5312da14cebeSEric Cheng static int
mac_group_mov_ring(mac_impl_t * mip,mac_group_t * d_group,mac_ring_t * ring)5313da14cebeSEric Cheng mac_group_mov_ring(mac_impl_t *mip, mac_group_t *d_group, mac_ring_t *ring)
5314da14cebeSEric Cheng {
5315da14cebeSEric Cheng mac_group_t *s_group = (mac_group_t *)ring->mr_gh;
5316da14cebeSEric Cheng int rv;
5317da14cebeSEric Cheng
5318da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5319da14cebeSEric Cheng ASSERT(d_group != NULL);
5320c85f09ccSJohn Levon ASSERT(s_group == NULL || s_group->mrg_mh == d_group->mrg_mh);
5321da14cebeSEric Cheng
5322da14cebeSEric Cheng if (s_group == d_group)
5323da14cebeSEric Cheng return (0);
5324da14cebeSEric Cheng
5325da14cebeSEric Cheng /*
5326da14cebeSEric Cheng * Remove it from current group first.
5327da14cebeSEric Cheng */
5328da14cebeSEric Cheng if (s_group != NULL)
5329da14cebeSEric Cheng i_mac_group_rem_ring(s_group, ring, B_FALSE);
5330da14cebeSEric Cheng
5331da14cebeSEric Cheng /*
5332da14cebeSEric Cheng * Add it to the new group.
5333da14cebeSEric Cheng */
5334da14cebeSEric Cheng rv = i_mac_group_add_ring(d_group, ring, 0);
5335da14cebeSEric Cheng if (rv != 0) {
5336da14cebeSEric Cheng /*
5337da14cebeSEric Cheng * Failed to add ring back to source group. If
5338da14cebeSEric Cheng * that fails, the ring is stuck in limbo, log message.
5339da14cebeSEric Cheng */
5340da14cebeSEric Cheng if (i_mac_group_add_ring(s_group, ring, 0)) {
5341da14cebeSEric Cheng cmn_err(CE_WARN, "%s: failed to move ring %p\n",
5342da14cebeSEric Cheng mip->mi_name, (void *)ring);
5343da14cebeSEric Cheng }
5344da14cebeSEric Cheng }
5345da14cebeSEric Cheng
5346da14cebeSEric Cheng return (rv);
5347da14cebeSEric Cheng }
5348da14cebeSEric Cheng
5349da14cebeSEric Cheng /*
5350da14cebeSEric Cheng * Find a MAC address according to its value.
5351da14cebeSEric Cheng */
5352da14cebeSEric Cheng mac_address_t *
mac_find_macaddr(mac_impl_t * mip,uint8_t * mac_addr)5353da14cebeSEric Cheng mac_find_macaddr(mac_impl_t *mip, uint8_t *mac_addr)
5354da14cebeSEric Cheng {
5355da14cebeSEric Cheng mac_address_t *map;
5356da14cebeSEric Cheng
5357da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5358da14cebeSEric Cheng
5359da14cebeSEric Cheng for (map = mip->mi_addresses; map != NULL; map = map->ma_next) {
5360da14cebeSEric Cheng if (bcmp(mac_addr, map->ma_addr, map->ma_len) == 0)
5361da14cebeSEric Cheng break;
5362da14cebeSEric Cheng }
5363da14cebeSEric Cheng
5364da14cebeSEric Cheng return (map);
5365da14cebeSEric Cheng }
5366da14cebeSEric Cheng
5367da14cebeSEric Cheng /*
5368da14cebeSEric Cheng * Check whether the MAC address is shared by multiple clients.
5369da14cebeSEric Cheng */
5370da14cebeSEric Cheng boolean_t
mac_check_macaddr_shared(mac_address_t * map)5371da14cebeSEric Cheng mac_check_macaddr_shared(mac_address_t *map)
5372da14cebeSEric Cheng {
5373da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)map->ma_mip));
5374da14cebeSEric Cheng
5375da14cebeSEric Cheng return (map->ma_nusers > 1);
5376da14cebeSEric Cheng }
5377da14cebeSEric Cheng
5378da14cebeSEric Cheng /*
5379da14cebeSEric Cheng * Remove the specified MAC address from the MAC address list and free it.
5380da14cebeSEric Cheng */
5381da14cebeSEric Cheng static void
mac_free_macaddr(mac_address_t * map)5382da14cebeSEric Cheng mac_free_macaddr(mac_address_t *map)
5383da14cebeSEric Cheng {
5384da14cebeSEric Cheng mac_impl_t *mip = map->ma_mip;
5385da14cebeSEric Cheng
5386da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
538784de666eSRyan Zezeski VERIFY3P(mip->mi_addresses, !=, NULL);
5388da14cebeSEric Cheng
538984de666eSRyan Zezeski VERIFY3P(map, ==, mac_find_macaddr(mip, map->ma_addr));
539084de666eSRyan Zezeski VERIFY3P(map, !=, NULL);
539184de666eSRyan Zezeski VERIFY3S(map->ma_nusers, ==, 0);
539284de666eSRyan Zezeski VERIFY3P(map->ma_vlans, ==, NULL);
5393da14cebeSEric Cheng
5394da14cebeSEric Cheng if (map == mip->mi_addresses) {
5395da14cebeSEric Cheng mip->mi_addresses = map->ma_next;
5396da14cebeSEric Cheng } else {
5397da14cebeSEric Cheng mac_address_t *pre;
5398da14cebeSEric Cheng
5399da14cebeSEric Cheng pre = mip->mi_addresses;
5400da14cebeSEric Cheng while (pre->ma_next != map)
5401da14cebeSEric Cheng pre = pre->ma_next;
5402da14cebeSEric Cheng pre->ma_next = map->ma_next;
5403da14cebeSEric Cheng }
5404da14cebeSEric Cheng
5405da14cebeSEric Cheng kmem_free(map, sizeof (mac_address_t));
5406da14cebeSEric Cheng }
5407da14cebeSEric Cheng
540884de666eSRyan Zezeski static mac_vlan_t *
mac_find_vlan(mac_address_t * map,uint16_t vid)540984de666eSRyan Zezeski mac_find_vlan(mac_address_t *map, uint16_t vid)
541084de666eSRyan Zezeski {
541184de666eSRyan Zezeski mac_vlan_t *mvp;
541284de666eSRyan Zezeski
541384de666eSRyan Zezeski for (mvp = map->ma_vlans; mvp != NULL; mvp = mvp->mv_next) {
541484de666eSRyan Zezeski if (mvp->mv_vid == vid)
541584de666eSRyan Zezeski return (mvp);
541684de666eSRyan Zezeski }
541784de666eSRyan Zezeski
541884de666eSRyan Zezeski return (NULL);
541984de666eSRyan Zezeski }
542084de666eSRyan Zezeski
542184de666eSRyan Zezeski static mac_vlan_t *
mac_add_vlan(mac_address_t * map,uint16_t vid)542284de666eSRyan Zezeski mac_add_vlan(mac_address_t *map, uint16_t vid)
542384de666eSRyan Zezeski {
542484de666eSRyan Zezeski mac_vlan_t *mvp;
542584de666eSRyan Zezeski
5426da14cebeSEric Cheng /*
542784de666eSRyan Zezeski * We should never add the same {addr, VID} tuple more
542884de666eSRyan Zezeski * than once, but let's be sure.
542984de666eSRyan Zezeski */
543084de666eSRyan Zezeski for (mvp = map->ma_vlans; mvp != NULL; mvp = mvp->mv_next)
543184de666eSRyan Zezeski VERIFY3U(mvp->mv_vid, !=, vid);
543284de666eSRyan Zezeski
543384de666eSRyan Zezeski /* Add the VLAN to the head of the VLAN list. */
543484de666eSRyan Zezeski mvp = kmem_zalloc(sizeof (mac_vlan_t), KM_SLEEP);
543584de666eSRyan Zezeski mvp->mv_vid = vid;
543684de666eSRyan Zezeski mvp->mv_next = map->ma_vlans;
543784de666eSRyan Zezeski map->ma_vlans = mvp;
543884de666eSRyan Zezeski
543984de666eSRyan Zezeski return (mvp);
544084de666eSRyan Zezeski }
544184de666eSRyan Zezeski
544284de666eSRyan Zezeski static void
mac_rem_vlan(mac_address_t * map,mac_vlan_t * mvp)544384de666eSRyan Zezeski mac_rem_vlan(mac_address_t *map, mac_vlan_t *mvp)
544484de666eSRyan Zezeski {
544584de666eSRyan Zezeski mac_vlan_t *pre;
544684de666eSRyan Zezeski
544784de666eSRyan Zezeski if (map->ma_vlans == mvp) {
544884de666eSRyan Zezeski map->ma_vlans = mvp->mv_next;
544984de666eSRyan Zezeski } else {
545084de666eSRyan Zezeski pre = map->ma_vlans;
545184de666eSRyan Zezeski while (pre->mv_next != mvp) {
545284de666eSRyan Zezeski pre = pre->mv_next;
545384de666eSRyan Zezeski
545484de666eSRyan Zezeski /*
545584de666eSRyan Zezeski * We've reached the end of the list without
545684de666eSRyan Zezeski * finding mvp.
545784de666eSRyan Zezeski */
545884de666eSRyan Zezeski VERIFY3P(pre, !=, NULL);
545984de666eSRyan Zezeski }
546084de666eSRyan Zezeski pre->mv_next = mvp->mv_next;
546184de666eSRyan Zezeski }
546284de666eSRyan Zezeski
546384de666eSRyan Zezeski kmem_free(mvp, sizeof (mac_vlan_t));
546484de666eSRyan Zezeski }
546584de666eSRyan Zezeski
546684de666eSRyan Zezeski /*
546784de666eSRyan Zezeski * Create a new mac_address_t if this is the first use of the address
546884de666eSRyan Zezeski * or add a VID to an existing address. In either case, the
546984de666eSRyan Zezeski * mac_address_t acts as a list of {addr, VID} tuples where each tuple
547084de666eSRyan Zezeski * shares the same addr. If group is non-NULL then attempt to program
547184de666eSRyan Zezeski * the MAC's HW filters for this group. Otherwise, if group is NULL,
547284de666eSRyan Zezeski * then the MAC has no rings and there is nothing to program.
5473da14cebeSEric Cheng */
5474da14cebeSEric Cheng int
mac_add_macaddr_vlan(mac_impl_t * mip,mac_group_t * group,uint8_t * addr,uint16_t vid,boolean_t use_hw)547584de666eSRyan Zezeski mac_add_macaddr_vlan(mac_impl_t *mip, mac_group_t *group, uint8_t *addr,
547684de666eSRyan Zezeski uint16_t vid, boolean_t use_hw)
5477da14cebeSEric Cheng {
5478da14cebeSEric Cheng mac_address_t *map;
547984de666eSRyan Zezeski mac_vlan_t *mvp;
5480da14cebeSEric Cheng int err = 0;
5481da14cebeSEric Cheng boolean_t allocated_map = B_FALSE;
548284de666eSRyan Zezeski boolean_t hw_mac = B_FALSE;
548384de666eSRyan Zezeski boolean_t hw_vlan = B_FALSE;
5484da14cebeSEric Cheng
5485da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5486da14cebeSEric Cheng
548784de666eSRyan Zezeski map = mac_find_macaddr(mip, addr);
5488da14cebeSEric Cheng
5489da14cebeSEric Cheng /*
549084de666eSRyan Zezeski * If this is the first use of this MAC address then allocate
549184de666eSRyan Zezeski * and initialize a new structure.
5492da14cebeSEric Cheng */
5493da14cebeSEric Cheng if (map == NULL) {
5494da14cebeSEric Cheng map = kmem_zalloc(sizeof (mac_address_t), KM_SLEEP);
5495da14cebeSEric Cheng map->ma_len = mip->mi_type->mt_addr_length;
549684de666eSRyan Zezeski bcopy(addr, map->ma_addr, map->ma_len);
5497da14cebeSEric Cheng map->ma_nusers = 0;
5498da14cebeSEric Cheng map->ma_group = group;
5499da14cebeSEric Cheng map->ma_mip = mip;
550084de666eSRyan Zezeski map->ma_untagged = B_FALSE;
5501da14cebeSEric Cheng
550284de666eSRyan Zezeski /* Add the new MAC address to the head of the address list. */
5503da14cebeSEric Cheng map->ma_next = mip->mi_addresses;
5504da14cebeSEric Cheng mip->mi_addresses = map;
5505da14cebeSEric Cheng
5506da14cebeSEric Cheng allocated_map = B_TRUE;
5507da14cebeSEric Cheng }
5508da14cebeSEric Cheng
550984de666eSRyan Zezeski VERIFY(map->ma_group == NULL || map->ma_group == group);
55100dc2366fSVenugopal Iyer if (map->ma_group == NULL)
55110dc2366fSVenugopal Iyer map->ma_group = group;
5512da14cebeSEric Cheng
551384de666eSRyan Zezeski if (vid == VLAN_ID_NONE) {
551484de666eSRyan Zezeski map->ma_untagged = B_TRUE;
551584de666eSRyan Zezeski mvp = NULL;
551684de666eSRyan Zezeski } else {
551784de666eSRyan Zezeski mvp = mac_add_vlan(map, vid);
551884de666eSRyan Zezeski }
551984de666eSRyan Zezeski
5520da14cebeSEric Cheng /*
552184de666eSRyan Zezeski * Set the VLAN HW filter if:
552284de666eSRyan Zezeski *
552384de666eSRyan Zezeski * o the MAC's VLAN HW filtering is enabled, and
552484de666eSRyan Zezeski * o the address does not currently rely on promisc mode.
552584de666eSRyan Zezeski *
552684de666eSRyan Zezeski * This is called even when the client specifies an untagged
552784de666eSRyan Zezeski * address (VLAN_ID_NONE) because some MAC providers require
552884de666eSRyan Zezeski * setting additional bits to accept untagged traffic when
552984de666eSRyan Zezeski * VLAN HW filtering is enabled.
5530da14cebeSEric Cheng */
553184de666eSRyan Zezeski if (MAC_GROUP_HW_VLAN(group) &&
553284de666eSRyan Zezeski map->ma_type != MAC_ADDRESS_TYPE_UNICAST_PROMISC) {
553384de666eSRyan Zezeski if ((err = mac_group_addvlan(group, vid)) != 0)
553484de666eSRyan Zezeski goto bail;
553584de666eSRyan Zezeski
553684de666eSRyan Zezeski hw_vlan = B_TRUE;
553784de666eSRyan Zezeski }
553884de666eSRyan Zezeski
553984de666eSRyan Zezeski VERIFY3S(map->ma_nusers, >=, 0);
554084de666eSRyan Zezeski map->ma_nusers++;
554184de666eSRyan Zezeski
554284de666eSRyan Zezeski /*
554384de666eSRyan Zezeski * If this MAC address already has a HW filter then simply
554484de666eSRyan Zezeski * increment the counter.
554584de666eSRyan Zezeski */
554684de666eSRyan Zezeski if (map->ma_nusers > 1)
5547da14cebeSEric Cheng return (0);
5548da14cebeSEric Cheng
5549da14cebeSEric Cheng /*
555084de666eSRyan Zezeski * All logic from here on out is executed during initial
555184de666eSRyan Zezeski * creation only.
555284de666eSRyan Zezeski */
555384de666eSRyan Zezeski VERIFY3S(map->ma_nusers, ==, 1);
555484de666eSRyan Zezeski
555584de666eSRyan Zezeski /*
5556da14cebeSEric Cheng * Activate this MAC address by adding it to the reserved group.
5557da14cebeSEric Cheng */
5558da14cebeSEric Cheng if (group != NULL) {
555984de666eSRyan Zezeski err = mac_group_addmac(group, (const uint8_t *)addr);
556084de666eSRyan Zezeski
556184de666eSRyan Zezeski /*
556284de666eSRyan Zezeski * If the driver is out of filters then we can
556384de666eSRyan Zezeski * continue and use promisc mode. For any other error,
556484de666eSRyan Zezeski * assume the driver is in a state where we can't
556584de666eSRyan Zezeski * program the filters or use promisc mode; so we must
556684de666eSRyan Zezeski * bail.
556784de666eSRyan Zezeski */
556884de666eSRyan Zezeski if (err != 0 && err != ENOSPC) {
556984de666eSRyan Zezeski map->ma_nusers--;
557084de666eSRyan Zezeski goto bail;
557184de666eSRyan Zezeski }
557284de666eSRyan Zezeski
557384de666eSRyan Zezeski hw_mac = (err == 0);
557484de666eSRyan Zezeski }
557584de666eSRyan Zezeski
557684de666eSRyan Zezeski if (hw_mac) {
5577da14cebeSEric Cheng map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5578da14cebeSEric Cheng return (0);
5579da14cebeSEric Cheng }
5580da14cebeSEric Cheng
5581da14cebeSEric Cheng /*
558208ac1c49SNicolas Droux * The MAC address addition failed. If the client requires a
558384de666eSRyan Zezeski * hardware classified MAC address, fail the operation. This
558484de666eSRyan Zezeski * feature is only used by sun4v vsw.
5585da14cebeSEric Cheng */
558684de666eSRyan Zezeski if (use_hw && !hw_mac) {
558708ac1c49SNicolas Droux err = ENOSPC;
558884de666eSRyan Zezeski map->ma_nusers--;
558908ac1c49SNicolas Droux goto bail;
559008ac1c49SNicolas Droux }
559108ac1c49SNicolas Droux
5592da14cebeSEric Cheng /*
559384de666eSRyan Zezeski * If we reach this point then either the MAC doesn't have
559484de666eSRyan Zezeski * RINGS capability or we are out of MAC address HW filters.
559584de666eSRyan Zezeski * In any case we must put the MAC into promiscuous mode.
559684de666eSRyan Zezeski */
559784de666eSRyan Zezeski VERIFY(group == NULL || !hw_mac);
559884de666eSRyan Zezeski
559984de666eSRyan Zezeski /*
560084de666eSRyan Zezeski * The one exception is the primary address. A non-RINGS
560184de666eSRyan Zezeski * driver filters the primary address by default; promisc mode
560284de666eSRyan Zezeski * is not needed.
5603da14cebeSEric Cheng */
5604da14cebeSEric Cheng if ((group == NULL) &&
5605da14cebeSEric Cheng (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0)) {
5606da14cebeSEric Cheng map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5607da14cebeSEric Cheng return (0);
5608da14cebeSEric Cheng }
5609da14cebeSEric Cheng
5610da14cebeSEric Cheng /*
561184de666eSRyan Zezeski * Enable promiscuous mode in order to receive traffic to the
561284de666eSRyan Zezeski * new MAC address. All existing HW filters still send their
561384de666eSRyan Zezeski * traffic to their respective group/SRSes. But with promisc
561484de666eSRyan Zezeski * enabled all unknown traffic is delivered to the default
561584de666eSRyan Zezeski * group where it is SW classified via mac_rx_classify().
5616da14cebeSEric Cheng */
5617d91a22bfSGirish Moodalbail if ((err = i_mac_promisc_set(mip, B_TRUE)) == 0) {
5618da14cebeSEric Cheng map->ma_type = MAC_ADDRESS_TYPE_UNICAST_PROMISC;
5619da14cebeSEric Cheng return (0);
5620da14cebeSEric Cheng }
5621da14cebeSEric Cheng
5622da14cebeSEric Cheng /*
562384de666eSRyan Zezeski * We failed to set promisc mode and we are about to free 'map'.
5624da14cebeSEric Cheng */
562584de666eSRyan Zezeski map->ma_nusers = 0;
562684de666eSRyan Zezeski
562708ac1c49SNicolas Droux bail:
562884de666eSRyan Zezeski if (hw_vlan) {
562984de666eSRyan Zezeski int err2 = mac_group_remvlan(group, vid);
563084de666eSRyan Zezeski
563184de666eSRyan Zezeski if (err2 != 0) {
563284de666eSRyan Zezeski cmn_err(CE_WARN, "Failed to remove VLAN %u from group"
563384de666eSRyan Zezeski " %d on MAC %s: %d.", vid, group->mrg_index,
563484de666eSRyan Zezeski mip->mi_name, err2);
563584de666eSRyan Zezeski }
563684de666eSRyan Zezeski }
563784de666eSRyan Zezeski
563884de666eSRyan Zezeski if (mvp != NULL)
563984de666eSRyan Zezeski mac_rem_vlan(map, mvp);
564084de666eSRyan Zezeski
5641da14cebeSEric Cheng if (allocated_map)
5642da14cebeSEric Cheng mac_free_macaddr(map);
564384de666eSRyan Zezeski
5644da14cebeSEric Cheng return (err);
5645da14cebeSEric Cheng }
5646da14cebeSEric Cheng
5647da14cebeSEric Cheng int
mac_remove_macaddr_vlan(mac_address_t * map,uint16_t vid)564884de666eSRyan Zezeski mac_remove_macaddr_vlan(mac_address_t *map, uint16_t vid)
5649da14cebeSEric Cheng {
565084de666eSRyan Zezeski mac_vlan_t *mvp;
5651da14cebeSEric Cheng mac_impl_t *mip = map->ma_mip;
565284de666eSRyan Zezeski mac_group_t *group = map->ma_group;
5653da14cebeSEric Cheng int err = 0;
5654da14cebeSEric Cheng
5655da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
565684de666eSRyan Zezeski VERIFY3P(map, ==, mac_find_macaddr(mip, map->ma_addr));
5657da14cebeSEric Cheng
565884de666eSRyan Zezeski if (vid == VLAN_ID_NONE) {
565984de666eSRyan Zezeski map->ma_untagged = B_FALSE;
566084de666eSRyan Zezeski mvp = NULL;
566184de666eSRyan Zezeski } else {
566284de666eSRyan Zezeski mvp = mac_find_vlan(map, vid);
566384de666eSRyan Zezeski VERIFY3P(mvp, !=, NULL);
566484de666eSRyan Zezeski }
566584de666eSRyan Zezeski
566684de666eSRyan Zezeski if (MAC_GROUP_HW_VLAN(group) &&
566784de666eSRyan Zezeski map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED &&
566884de666eSRyan Zezeski ((err = mac_group_remvlan(group, vid)) != 0))
566984de666eSRyan Zezeski return (err);
567084de666eSRyan Zezeski
567184de666eSRyan Zezeski if (mvp != NULL)
567284de666eSRyan Zezeski mac_rem_vlan(map, mvp);
5673da14cebeSEric Cheng
5674da14cebeSEric Cheng /*
5675da14cebeSEric Cheng * If it's not the last client using this MAC address, only update
5676da14cebeSEric Cheng * the MAC clients count.
5677da14cebeSEric Cheng */
567884de666eSRyan Zezeski map->ma_nusers--;
567984de666eSRyan Zezeski if (map->ma_nusers > 0)
5680da14cebeSEric Cheng return (0);
5681da14cebeSEric Cheng
568284de666eSRyan Zezeski VERIFY3S(map->ma_nusers, ==, 0);
568384de666eSRyan Zezeski
5684da14cebeSEric Cheng /*
568584de666eSRyan Zezeski * The MAC address is no longer used by any MAC client, so
568684de666eSRyan Zezeski * remove it from its associated group. Turn off promiscuous
568784de666eSRyan Zezeski * mode if this is the last address relying on it.
5688da14cebeSEric Cheng */
5689da14cebeSEric Cheng switch (map->ma_type) {
5690da14cebeSEric Cheng case MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED:
5691da14cebeSEric Cheng /*
5692da14cebeSEric Cheng * Don't free the preset primary address for drivers that
5693da14cebeSEric Cheng * don't advertise RINGS capability.
5694da14cebeSEric Cheng */
569584de666eSRyan Zezeski if (group == NULL)
5696da14cebeSEric Cheng return (0);
5697da14cebeSEric Cheng
569884de666eSRyan Zezeski if ((err = mac_group_remmac(group, map->ma_addr)) != 0) {
569984de666eSRyan Zezeski if (vid == VLAN_ID_NONE)
570084de666eSRyan Zezeski map->ma_untagged = B_TRUE;
570184de666eSRyan Zezeski else
570284de666eSRyan Zezeski (void) mac_add_vlan(map, vid);
570384de666eSRyan Zezeski
570484de666eSRyan Zezeski /*
570584de666eSRyan Zezeski * If we fail to remove the MAC address HW
570684de666eSRyan Zezeski * filter but then also fail to re-add the
570784de666eSRyan Zezeski * VLAN HW filter then we are in a busted
570884de666eSRyan Zezeski * state. We do our best by logging a warning
570984de666eSRyan Zezeski * and returning the original 'err' that got
571084de666eSRyan Zezeski * us here. At this point, traffic for this
571184de666eSRyan Zezeski * address + VLAN combination will be dropped
571284de666eSRyan Zezeski * until the user reboots the system. In the
571384de666eSRyan Zezeski * future, it would be nice to have a system
571484de666eSRyan Zezeski * that can compare the state of expected
571584de666eSRyan Zezeski * classification according to mac to the
571684de666eSRyan Zezeski * actual state of the provider, and report
571784de666eSRyan Zezeski * and fix any inconsistencies.
571884de666eSRyan Zezeski */
571984de666eSRyan Zezeski if (MAC_GROUP_HW_VLAN(group)) {
572084de666eSRyan Zezeski int err2;
572184de666eSRyan Zezeski
572284de666eSRyan Zezeski err2 = mac_group_addvlan(group, vid);
572384de666eSRyan Zezeski if (err2 != 0) {
572484de666eSRyan Zezeski cmn_err(CE_WARN, "Failed to readd VLAN"
572584de666eSRyan Zezeski " %u to group %d on MAC %s: %d.",
572684de666eSRyan Zezeski vid, group->mrg_index, mip->mi_name,
572784de666eSRyan Zezeski err2);
572884de666eSRyan Zezeski }
572984de666eSRyan Zezeski }
573084de666eSRyan Zezeski
573184de666eSRyan Zezeski map->ma_nusers = 1;
573284de666eSRyan Zezeski return (err);
573384de666eSRyan Zezeski }
573484de666eSRyan Zezeski
57350dc2366fSVenugopal Iyer map->ma_group = NULL;
5736da14cebeSEric Cheng break;
5737da14cebeSEric Cheng case MAC_ADDRESS_TYPE_UNICAST_PROMISC:
5738d91a22bfSGirish Moodalbail err = i_mac_promisc_set(mip, B_FALSE);
5739da14cebeSEric Cheng break;
5740da14cebeSEric Cheng default:
574184de666eSRyan Zezeski panic("Unexpected ma_type 0x%x, file: %s, line %d",
574284de666eSRyan Zezeski map->ma_type, __FILE__, __LINE__);
5743da14cebeSEric Cheng }
5744da14cebeSEric Cheng
574584de666eSRyan Zezeski if (err != 0) {
574684de666eSRyan Zezeski map->ma_nusers = 1;
5747da14cebeSEric Cheng return (err);
574884de666eSRyan Zezeski }
5749da14cebeSEric Cheng
5750da14cebeSEric Cheng /*
5751da14cebeSEric Cheng * We created MAC address for the primary one at registration, so we
5752da14cebeSEric Cheng * won't free it here. mac_fini_macaddr() will take care of it.
5753da14cebeSEric Cheng */
5754da14cebeSEric Cheng if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) != 0)
5755da14cebeSEric Cheng mac_free_macaddr(map);
5756da14cebeSEric Cheng
5757da14cebeSEric Cheng return (0);
5758da14cebeSEric Cheng }
5759da14cebeSEric Cheng
5760da14cebeSEric Cheng /*
5761da14cebeSEric Cheng * Update an existing MAC address. The caller need to make sure that the new
5762da14cebeSEric Cheng * value has not been used.
5763da14cebeSEric Cheng */
5764da14cebeSEric Cheng int
mac_update_macaddr(mac_address_t * map,uint8_t * mac_addr)5765da14cebeSEric Cheng mac_update_macaddr(mac_address_t *map, uint8_t *mac_addr)
5766da14cebeSEric Cheng {
5767da14cebeSEric Cheng mac_impl_t *mip = map->ma_mip;
5768da14cebeSEric Cheng int err = 0;
5769da14cebeSEric Cheng
5770da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5771da14cebeSEric Cheng ASSERT(mac_find_macaddr(mip, mac_addr) == NULL);
5772da14cebeSEric Cheng
5773da14cebeSEric Cheng switch (map->ma_type) {
5774da14cebeSEric Cheng case MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED:
5775da14cebeSEric Cheng /*
5776da14cebeSEric Cheng * Update the primary address for drivers that are not
5777da14cebeSEric Cheng * RINGS capable.
5778da14cebeSEric Cheng */
57790dc2366fSVenugopal Iyer if (mip->mi_rx_groups == NULL) {
5780da14cebeSEric Cheng err = mip->mi_unicst(mip->mi_driver, (const uint8_t *)
5781da14cebeSEric Cheng mac_addr);
5782da14cebeSEric Cheng if (err != 0)
5783da14cebeSEric Cheng return (err);
5784da14cebeSEric Cheng break;
5785da14cebeSEric Cheng }
5786da14cebeSEric Cheng
5787da14cebeSEric Cheng /*
5788da14cebeSEric Cheng * If this MAC address is not currently in use,
5789da14cebeSEric Cheng * simply break out and update the value.
5790da14cebeSEric Cheng */
5791da14cebeSEric Cheng if (map->ma_nusers == 0)
5792da14cebeSEric Cheng break;
5793da14cebeSEric Cheng
5794da14cebeSEric Cheng /*
5795da14cebeSEric Cheng * Need to replace the MAC address associated with a group.
5796da14cebeSEric Cheng */
5797da14cebeSEric Cheng err = mac_group_remmac(map->ma_group, map->ma_addr);
5798da14cebeSEric Cheng if (err != 0)
5799da14cebeSEric Cheng return (err);
5800da14cebeSEric Cheng
5801da14cebeSEric Cheng err = mac_group_addmac(map->ma_group, mac_addr);
5802da14cebeSEric Cheng
5803da14cebeSEric Cheng /*
5804da14cebeSEric Cheng * Failure hints hardware error. The MAC layer needs to
5805da14cebeSEric Cheng * have error notification facility to handle this.
5806da14cebeSEric Cheng * Now, simply try to restore the value.
5807da14cebeSEric Cheng */
5808da14cebeSEric Cheng if (err != 0)
5809da14cebeSEric Cheng (void) mac_group_addmac(map->ma_group, map->ma_addr);
5810da14cebeSEric Cheng
5811da14cebeSEric Cheng break;
5812da14cebeSEric Cheng case MAC_ADDRESS_TYPE_UNICAST_PROMISC:
5813da14cebeSEric Cheng /*
5814da14cebeSEric Cheng * Need to do nothing more if in promiscuous mode.
5815da14cebeSEric Cheng */
5816da14cebeSEric Cheng break;
5817da14cebeSEric Cheng default:
5818da14cebeSEric Cheng ASSERT(B_FALSE);
5819da14cebeSEric Cheng }
5820da14cebeSEric Cheng
5821da14cebeSEric Cheng /*
5822da14cebeSEric Cheng * Successfully replaced the MAC address.
5823da14cebeSEric Cheng */
5824da14cebeSEric Cheng if (err == 0)
5825da14cebeSEric Cheng bcopy(mac_addr, map->ma_addr, map->ma_len);
5826da14cebeSEric Cheng
5827da14cebeSEric Cheng return (err);
5828da14cebeSEric Cheng }
5829da14cebeSEric Cheng
5830da14cebeSEric Cheng /*
5831da14cebeSEric Cheng * Freshen the MAC address with new value. Its caller must have updated the
5832da14cebeSEric Cheng * hardware MAC address before calling this function.
5833da14cebeSEric Cheng * This funcitons is supposed to be used to handle the MAC address change
5834da14cebeSEric Cheng * notification from underlying drivers.
5835da14cebeSEric Cheng */
5836da14cebeSEric Cheng void
mac_freshen_macaddr(mac_address_t * map,uint8_t * mac_addr)5837da14cebeSEric Cheng mac_freshen_macaddr(mac_address_t *map, uint8_t *mac_addr)
5838da14cebeSEric Cheng {
5839da14cebeSEric Cheng mac_impl_t *mip = map->ma_mip;
5840da14cebeSEric Cheng
5841da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5842da14cebeSEric Cheng ASSERT(mac_find_macaddr(mip, mac_addr) == NULL);
5843da14cebeSEric Cheng
5844da14cebeSEric Cheng /*
5845da14cebeSEric Cheng * Freshen the MAC address with new value.
5846da14cebeSEric Cheng */
5847da14cebeSEric Cheng bcopy(mac_addr, map->ma_addr, map->ma_len);
5848da14cebeSEric Cheng bcopy(mac_addr, mip->mi_addr, map->ma_len);
5849da14cebeSEric Cheng
5850da14cebeSEric Cheng /*
5851da14cebeSEric Cheng * Update all MAC clients that share this MAC address.
5852da14cebeSEric Cheng */
5853da14cebeSEric Cheng mac_unicast_update_clients(mip, map);
5854da14cebeSEric Cheng }
5855da14cebeSEric Cheng
5856da14cebeSEric Cheng /*
5857da14cebeSEric Cheng * Set up the primary MAC address.
5858da14cebeSEric Cheng */
5859da14cebeSEric Cheng void
mac_init_macaddr(mac_impl_t * mip)5860da14cebeSEric Cheng mac_init_macaddr(mac_impl_t *mip)
5861da14cebeSEric Cheng {
5862da14cebeSEric Cheng mac_address_t *map;
5863da14cebeSEric Cheng
5864da14cebeSEric Cheng /*
5865da14cebeSEric Cheng * The reference count is initialized to zero, until it's really
5866da14cebeSEric Cheng * activated.
5867da14cebeSEric Cheng */
5868da14cebeSEric Cheng map = kmem_zalloc(sizeof (mac_address_t), KM_SLEEP);
5869da14cebeSEric Cheng map->ma_len = mip->mi_type->mt_addr_length;
5870da14cebeSEric Cheng bcopy(mip->mi_addr, map->ma_addr, map->ma_len);
5871da14cebeSEric Cheng
5872da14cebeSEric Cheng /*
5873da14cebeSEric Cheng * If driver advertises RINGS capability, it shouldn't have initialized
5874da14cebeSEric Cheng * its primary MAC address. For other drivers, including VNIC, the
5875da14cebeSEric Cheng * primary address must work after registration.
5876da14cebeSEric Cheng */
5877da14cebeSEric Cheng if (mip->mi_rx_groups == NULL)
5878da14cebeSEric Cheng map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5879da14cebeSEric Cheng
5880da14cebeSEric Cheng map->ma_mip = mip;
5881da14cebeSEric Cheng
5882da14cebeSEric Cheng mip->mi_addresses = map;
5883da14cebeSEric Cheng }
5884da14cebeSEric Cheng
5885da14cebeSEric Cheng /*
5886da14cebeSEric Cheng * Clean up the primary MAC address. Note, only one primary MAC address
5887da14cebeSEric Cheng * is allowed. All other MAC addresses must have been freed appropriately.
5888da14cebeSEric Cheng */
5889da14cebeSEric Cheng void
mac_fini_macaddr(mac_impl_t * mip)5890da14cebeSEric Cheng mac_fini_macaddr(mac_impl_t *mip)
5891da14cebeSEric Cheng {
5892da14cebeSEric Cheng mac_address_t *map = mip->mi_addresses;
5893da14cebeSEric Cheng
5894ae6aa22aSVenugopal Iyer if (map == NULL)
5895ae6aa22aSVenugopal Iyer return;
5896ae6aa22aSVenugopal Iyer
5897ae6aa22aSVenugopal Iyer /*
5898ae6aa22aSVenugopal Iyer * If mi_addresses is initialized, there should be exactly one
5899ae6aa22aSVenugopal Iyer * entry left on the list with no users.
5900ae6aa22aSVenugopal Iyer */
590184de666eSRyan Zezeski VERIFY3S(map->ma_nusers, ==, 0);
590284de666eSRyan Zezeski VERIFY3P(map->ma_next, ==, NULL);
590384de666eSRyan Zezeski VERIFY3P(map->ma_vlans, ==, NULL);
5904da14cebeSEric Cheng
5905da14cebeSEric Cheng kmem_free(map, sizeof (mac_address_t));
5906da14cebeSEric Cheng mip->mi_addresses = NULL;
5907da14cebeSEric Cheng }
5908da14cebeSEric Cheng
5909da14cebeSEric Cheng /*
5910da14cebeSEric Cheng * Logging related functions.
59110dc2366fSVenugopal Iyer *
59120dc2366fSVenugopal Iyer * Note that Kernel statistics have been extended to maintain fine
59130dc2366fSVenugopal Iyer * granularity of statistics viz. hardware lane, software lane, fanout
59140dc2366fSVenugopal Iyer * stats etc. However, extended accounting continues to support only
59150dc2366fSVenugopal Iyer * aggregate statistics like before.
5916da14cebeSEric Cheng */
5917da14cebeSEric Cheng
5918c228408bSMichael Lim /* Write the flow description to a netinfo_t record */
5919c228408bSMichael Lim static netinfo_t *
mac_write_flow_desc(flow_entry_t * flent,mac_client_impl_t * mcip)5920da14cebeSEric Cheng mac_write_flow_desc(flow_entry_t *flent, mac_client_impl_t *mcip)
5921da14cebeSEric Cheng {
5922c228408bSMichael Lim netinfo_t *ninfo;
5923c228408bSMichael Lim net_desc_t *ndesc;
5924da14cebeSEric Cheng flow_desc_t *fdesc;
5925da14cebeSEric Cheng mac_resource_props_t *mrp;
5926da14cebeSEric Cheng
5927c228408bSMichael Lim ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
5928c228408bSMichael Lim if (ninfo == NULL)
5929c228408bSMichael Lim return (NULL);
5930c228408bSMichael Lim ndesc = kmem_zalloc(sizeof (net_desc_t), KM_NOSLEEP);
5931c228408bSMichael Lim if (ndesc == NULL) {
5932c228408bSMichael Lim kmem_free(ninfo, sizeof (netinfo_t));
5933c228408bSMichael Lim return (NULL);
5934c228408bSMichael Lim }
5935da14cebeSEric Cheng
5936da14cebeSEric Cheng /*
5937da14cebeSEric Cheng * Grab the fe_lock to see a self-consistent fe_flow_desc.
5938da14cebeSEric Cheng * Updates to the fe_flow_desc are done under the fe_lock
5939da14cebeSEric Cheng */
5940da14cebeSEric Cheng mutex_enter(&flent->fe_lock);
5941da14cebeSEric Cheng fdesc = &flent->fe_flow_desc;
5942da14cebeSEric Cheng mrp = &flent->fe_resource_props;
5943da14cebeSEric Cheng
5944c228408bSMichael Lim ndesc->nd_name = flent->fe_flow_name;
5945c228408bSMichael Lim ndesc->nd_devname = mcip->mci_name;
5946c228408bSMichael Lim bcopy(fdesc->fd_src_mac, ndesc->nd_ehost, ETHERADDRL);
5947c228408bSMichael Lim bcopy(fdesc->fd_dst_mac, ndesc->nd_edest, ETHERADDRL);
5948c228408bSMichael Lim ndesc->nd_sap = htonl(fdesc->fd_sap);
5949c228408bSMichael Lim ndesc->nd_isv4 = (uint8_t)fdesc->fd_ipversion == IPV4_VERSION;
5950c228408bSMichael Lim ndesc->nd_bw_limit = mrp->mrp_maxbw;
5951c228408bSMichael Lim if (ndesc->nd_isv4) {
5952c228408bSMichael Lim ndesc->nd_saddr[3] = htonl(fdesc->fd_local_addr.s6_addr32[3]);
5953c228408bSMichael Lim ndesc->nd_daddr[3] = htonl(fdesc->fd_remote_addr.s6_addr32[3]);
5954da14cebeSEric Cheng } else {
5955c228408bSMichael Lim bcopy(&fdesc->fd_local_addr, ndesc->nd_saddr, IPV6_ADDR_LEN);
5956c228408bSMichael Lim bcopy(&fdesc->fd_remote_addr, ndesc->nd_daddr, IPV6_ADDR_LEN);
5957da14cebeSEric Cheng }
5958c228408bSMichael Lim ndesc->nd_sport = htons(fdesc->fd_local_port);
5959c228408bSMichael Lim ndesc->nd_dport = htons(fdesc->fd_remote_port);
5960c228408bSMichael Lim ndesc->nd_protocol = (uint8_t)fdesc->fd_protocol;
5961da14cebeSEric Cheng mutex_exit(&flent->fe_lock);
5962da14cebeSEric Cheng
5963c228408bSMichael Lim ninfo->ni_record = ndesc;
5964c228408bSMichael Lim ninfo->ni_size = sizeof (net_desc_t);
5965c228408bSMichael Lim ninfo->ni_type = EX_NET_FLDESC_REC;
5966c228408bSMichael Lim
5967c228408bSMichael Lim return (ninfo);
5968da14cebeSEric Cheng }
5969da14cebeSEric Cheng
5970c228408bSMichael Lim /* Write the flow statistics to a netinfo_t record */
5971c228408bSMichael Lim static netinfo_t *
mac_write_flow_stats(flow_entry_t * flent)5972da14cebeSEric Cheng mac_write_flow_stats(flow_entry_t *flent)
5973da14cebeSEric Cheng {
5974c228408bSMichael Lim netinfo_t *ninfo;
5975c228408bSMichael Lim net_stat_t *nstat;
59760dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
59770dc2366fSVenugopal Iyer mac_rx_stats_t *mac_rx_stat;
59780dc2366fSVenugopal Iyer mac_tx_stats_t *mac_tx_stat;
59790dc2366fSVenugopal Iyer int i;
5980da14cebeSEric Cheng
5981c228408bSMichael Lim ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
5982c228408bSMichael Lim if (ninfo == NULL)
5983c228408bSMichael Lim return (NULL);
5984c228408bSMichael Lim nstat = kmem_zalloc(sizeof (net_stat_t), KM_NOSLEEP);
5985c228408bSMichael Lim if (nstat == NULL) {
5986c228408bSMichael Lim kmem_free(ninfo, sizeof (netinfo_t));
5987c228408bSMichael Lim return (NULL);
5988c228408bSMichael Lim }
5989c228408bSMichael Lim
5990c228408bSMichael Lim nstat->ns_name = flent->fe_flow_name;
59910dc2366fSVenugopal Iyer for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
59920dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
59930dc2366fSVenugopal Iyer mac_rx_stat = &mac_srs->srs_rx.sr_stat;
5994da14cebeSEric Cheng
5995c228408bSMichael Lim nstat->ns_ibytes += mac_rx_stat->mrs_intrbytes +
59960dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollbytes + mac_rx_stat->mrs_lclbytes;
5997c228408bSMichael Lim nstat->ns_ipackets += mac_rx_stat->mrs_intrcnt +
59980dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
5999c228408bSMichael Lim nstat->ns_oerrors += mac_rx_stat->mrs_ierrors;
60000dc2366fSVenugopal Iyer }
60010dc2366fSVenugopal Iyer
60020dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs);
60030dc2366fSVenugopal Iyer if (mac_srs != NULL) {
60040dc2366fSVenugopal Iyer mac_tx_stat = &mac_srs->srs_tx.st_stat;
60050dc2366fSVenugopal Iyer
6006c228408bSMichael Lim nstat->ns_obytes = mac_tx_stat->mts_obytes;
6007c228408bSMichael Lim nstat->ns_opackets = mac_tx_stat->mts_opackets;
6008c228408bSMichael Lim nstat->ns_oerrors = mac_tx_stat->mts_oerrors;
6009da14cebeSEric Cheng }
6010da14cebeSEric Cheng
6011c228408bSMichael Lim ninfo->ni_record = nstat;
6012c228408bSMichael Lim ninfo->ni_size = sizeof (net_stat_t);
6013c228408bSMichael Lim ninfo->ni_type = EX_NET_FLSTAT_REC;
6014c228408bSMichael Lim
6015c228408bSMichael Lim return (ninfo);
6016c228408bSMichael Lim }
6017c228408bSMichael Lim
6018c228408bSMichael Lim /* Write the link description to a netinfo_t record */
6019c228408bSMichael Lim static netinfo_t *
mac_write_link_desc(mac_client_impl_t * mcip)6020da14cebeSEric Cheng mac_write_link_desc(mac_client_impl_t *mcip)
6021da14cebeSEric Cheng {
6022c228408bSMichael Lim netinfo_t *ninfo;
6023c228408bSMichael Lim net_desc_t *ndesc;
6024da14cebeSEric Cheng flow_entry_t *flent = mcip->mci_flent;
6025da14cebeSEric Cheng
6026c228408bSMichael Lim ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
6027c228408bSMichael Lim if (ninfo == NULL)
6028c228408bSMichael Lim return (NULL);
6029c228408bSMichael Lim ndesc = kmem_zalloc(sizeof (net_desc_t), KM_NOSLEEP);
6030c228408bSMichael Lim if (ndesc == NULL) {
6031c228408bSMichael Lim kmem_free(ninfo, sizeof (netinfo_t));
6032c228408bSMichael Lim return (NULL);
6033c228408bSMichael Lim }
6034da14cebeSEric Cheng
6035c228408bSMichael Lim ndesc->nd_name = mcip->mci_name;
6036c228408bSMichael Lim ndesc->nd_devname = mcip->mci_name;
6037c228408bSMichael Lim ndesc->nd_isv4 = B_TRUE;
6038da14cebeSEric Cheng /*
6039da14cebeSEric Cheng * Grab the fe_lock to see a self-consistent fe_flow_desc.
6040da14cebeSEric Cheng * Updates to the fe_flow_desc are done under the fe_lock
6041da14cebeSEric Cheng * after removing the flent from the flow table.
6042da14cebeSEric Cheng */
6043da14cebeSEric Cheng mutex_enter(&flent->fe_lock);
6044c228408bSMichael Lim bcopy(flent->fe_flow_desc.fd_src_mac, ndesc->nd_ehost, ETHERADDRL);
6045da14cebeSEric Cheng mutex_exit(&flent->fe_lock);
6046da14cebeSEric Cheng
6047c228408bSMichael Lim ninfo->ni_record = ndesc;
6048c228408bSMichael Lim ninfo->ni_size = sizeof (net_desc_t);
6049c228408bSMichael Lim ninfo->ni_type = EX_NET_LNDESC_REC;
6050c228408bSMichael Lim
6051c228408bSMichael Lim return (ninfo);
6052da14cebeSEric Cheng }
6053da14cebeSEric Cheng
6054c228408bSMichael Lim /* Write the link statistics to a netinfo_t record */
6055c228408bSMichael Lim static netinfo_t *
mac_write_link_stats(mac_client_impl_t * mcip)6056da14cebeSEric Cheng mac_write_link_stats(mac_client_impl_t *mcip)
6057da14cebeSEric Cheng {
6058c228408bSMichael Lim netinfo_t *ninfo;
6059c228408bSMichael Lim net_stat_t *nstat;
60600dc2366fSVenugopal Iyer flow_entry_t *flent;
60610dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs;
60620dc2366fSVenugopal Iyer mac_rx_stats_t *mac_rx_stat;
60630dc2366fSVenugopal Iyer mac_tx_stats_t *mac_tx_stat;
60640dc2366fSVenugopal Iyer int i;
6065da14cebeSEric Cheng
6066c228408bSMichael Lim ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
6067c228408bSMichael Lim if (ninfo == NULL)
6068c228408bSMichael Lim return (NULL);
6069c228408bSMichael Lim nstat = kmem_zalloc(sizeof (net_stat_t), KM_NOSLEEP);
6070c228408bSMichael Lim if (nstat == NULL) {
6071c228408bSMichael Lim kmem_free(ninfo, sizeof (netinfo_t));
6072c228408bSMichael Lim return (NULL);
6073c228408bSMichael Lim }
6074c228408bSMichael Lim
6075c228408bSMichael Lim nstat->ns_name = mcip->mci_name;
60760dc2366fSVenugopal Iyer flent = mcip->mci_flent;
60770dc2366fSVenugopal Iyer if (flent != NULL) {
60780dc2366fSVenugopal Iyer for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
60790dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
60800dc2366fSVenugopal Iyer mac_rx_stat = &mac_srs->srs_rx.sr_stat;
6081da14cebeSEric Cheng
6082c228408bSMichael Lim nstat->ns_ibytes += mac_rx_stat->mrs_intrbytes +
60830dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollbytes +
60840dc2366fSVenugopal Iyer mac_rx_stat->mrs_lclbytes;
6085c228408bSMichael Lim nstat->ns_ipackets += mac_rx_stat->mrs_intrcnt +
60860dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
6087c228408bSMichael Lim nstat->ns_oerrors += mac_rx_stat->mrs_ierrors;
60880dc2366fSVenugopal Iyer }
60890dc2366fSVenugopal Iyer }
60900dc2366fSVenugopal Iyer
60910dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)(mcip->mci_flent->fe_tx_srs);
60920dc2366fSVenugopal Iyer if (mac_srs != NULL) {
60930dc2366fSVenugopal Iyer mac_tx_stat = &mac_srs->srs_tx.st_stat;
60940dc2366fSVenugopal Iyer
6095c228408bSMichael Lim nstat->ns_obytes = mac_tx_stat->mts_obytes;
6096c228408bSMichael Lim nstat->ns_opackets = mac_tx_stat->mts_opackets;
6097c228408bSMichael Lim nstat->ns_oerrors = mac_tx_stat->mts_oerrors;
6098da14cebeSEric Cheng }
6099da14cebeSEric Cheng
6100c228408bSMichael Lim ninfo->ni_record = nstat;
6101c228408bSMichael Lim ninfo->ni_size = sizeof (net_stat_t);
6102c228408bSMichael Lim ninfo->ni_type = EX_NET_LNSTAT_REC;
6103c228408bSMichael Lim
6104c228408bSMichael Lim return (ninfo);
6105c228408bSMichael Lim }
6106c228408bSMichael Lim
6107c228408bSMichael Lim typedef struct i_mac_log_state_s {
6108c228408bSMichael Lim boolean_t mi_last;
6109c228408bSMichael Lim int mi_fenable;
6110c228408bSMichael Lim int mi_lenable;
6111c228408bSMichael Lim list_t *mi_list;
6112c228408bSMichael Lim } i_mac_log_state_t;
6113c228408bSMichael Lim
6114da14cebeSEric Cheng /*
6115c228408bSMichael Lim * For a given flow, if the description has not been logged before, do it now.
6116da14cebeSEric Cheng * If it is a VNIC, then we have collected information about it from the MAC
6117da14cebeSEric Cheng * table, so skip it.
6118c228408bSMichael Lim *
6119c228408bSMichael Lim * Called through mac_flow_walk_nolock()
6120c228408bSMichael Lim *
6121c228408bSMichael Lim * Return 0 if successful.
6122da14cebeSEric Cheng */
6123da14cebeSEric Cheng static int
mac_log_flowinfo(flow_entry_t * flent,void * arg)6124c228408bSMichael Lim mac_log_flowinfo(flow_entry_t *flent, void *arg)
6125da14cebeSEric Cheng {
6126da14cebeSEric Cheng mac_client_impl_t *mcip = flent->fe_mcip;
6127c228408bSMichael Lim i_mac_log_state_t *lstate = arg;
6128c228408bSMichael Lim netinfo_t *ninfo;
6129da14cebeSEric Cheng
6130da14cebeSEric Cheng if (mcip == NULL)
6131da14cebeSEric Cheng return (0);
6132da14cebeSEric Cheng
6133da14cebeSEric Cheng /*
6134da14cebeSEric Cheng * If the name starts with "vnic", and fe_user_generated is true (to
6135da14cebeSEric Cheng * exclude the mcast and active flow entries created implicitly for
6136da14cebeSEric Cheng * a vnic, it is a VNIC flow. i.e. vnic1 is a vnic flow,
6137da14cebeSEric Cheng * vnic/bge1/mcast1 is not and neither is vnic/bge1/active.
6138da14cebeSEric Cheng */
6139da14cebeSEric Cheng if (strncasecmp(flent->fe_flow_name, "vnic", 4) == 0 &&
6140da14cebeSEric Cheng (flent->fe_type & FLOW_USER) != 0) {
6141da14cebeSEric Cheng return (0);
6142da14cebeSEric Cheng }
6143da14cebeSEric Cheng
6144da14cebeSEric Cheng if (!flent->fe_desc_logged) {
6145da14cebeSEric Cheng /*
6146c228408bSMichael Lim * We don't return error because we want to continue the
6147da14cebeSEric Cheng * walk in case this is the last walk which means we
6148da14cebeSEric Cheng * need to reset fe_desc_logged in all the flows.
6149da14cebeSEric Cheng */
6150c228408bSMichael Lim if ((ninfo = mac_write_flow_desc(flent, mcip)) == NULL)
6151da14cebeSEric Cheng return (0);
6152c228408bSMichael Lim list_insert_tail(lstate->mi_list, ninfo);
6153da14cebeSEric Cheng flent->fe_desc_logged = B_TRUE;
6154da14cebeSEric Cheng }
6155da14cebeSEric Cheng
6156da14cebeSEric Cheng /*
6157da14cebeSEric Cheng * Regardless of the error, we want to proceed in case we have to
6158da14cebeSEric Cheng * reset fe_desc_logged.
6159da14cebeSEric Cheng */
6160c228408bSMichael Lim ninfo = mac_write_flow_stats(flent);
6161c228408bSMichael Lim if (ninfo == NULL)
6162c228408bSMichael Lim return (-1);
6163c228408bSMichael Lim
6164c228408bSMichael Lim list_insert_tail(lstate->mi_list, ninfo);
6165da14cebeSEric Cheng
6166da14cebeSEric Cheng if (mcip != NULL && !(mcip->mci_state_flags & MCIS_DESC_LOGGED))
6167da14cebeSEric Cheng flent->fe_desc_logged = B_FALSE;
6168da14cebeSEric Cheng
6169da14cebeSEric Cheng return (0);
6170da14cebeSEric Cheng }
6171da14cebeSEric Cheng
6172da14cebeSEric Cheng /*
6173c228408bSMichael Lim * Log the description for each mac client of this mac_impl_t, if it
6174c228408bSMichael Lim * hasn't already been done. Additionally, log statistics for the link as
6175da14cebeSEric Cheng * well. Walk the flow table and log information for each flow as well.
6176da14cebeSEric Cheng * If it is the last walk (mci_last), then we turn off mci_desc_logged (and
6177da14cebeSEric Cheng * also fe_desc_logged, if flow logging is on) since we want to log the
6178da14cebeSEric Cheng * description if and when logging is restarted.
6179c228408bSMichael Lim *
6180c228408bSMichael Lim * Return 0 upon success or -1 upon failure
6181da14cebeSEric Cheng */
6182c228408bSMichael Lim static int
i_mac_impl_log(mac_impl_t * mip,i_mac_log_state_t * lstate)6183c228408bSMichael Lim i_mac_impl_log(mac_impl_t *mip, i_mac_log_state_t *lstate)
6184da14cebeSEric Cheng {
6185da14cebeSEric Cheng mac_client_impl_t *mcip;
6186c228408bSMichael Lim netinfo_t *ninfo;
6187da14cebeSEric Cheng
6188c228408bSMichael Lim i_mac_perim_enter(mip);
6189da14cebeSEric Cheng /*
6190da14cebeSEric Cheng * Only walk the client list for NIC and etherstub
6191da14cebeSEric Cheng */
6192da14cebeSEric Cheng if ((mip->mi_state_flags & MIS_DISABLED) ||
6193da14cebeSEric Cheng ((mip->mi_state_flags & MIS_IS_VNIC) &&
6194c228408bSMichael Lim (mac_get_lower_mac_handle((mac_handle_t)mip) != NULL))) {
6195c228408bSMichael Lim i_mac_perim_exit(mip);
6196c228408bSMichael Lim return (0);
6197c228408bSMichael Lim }
6198da14cebeSEric Cheng
6199da14cebeSEric Cheng for (mcip = mip->mi_clients_list; mcip != NULL;
6200da14cebeSEric Cheng mcip = mcip->mci_client_next) {
6201da14cebeSEric Cheng if (!MCIP_DATAPATH_SETUP(mcip))
6202da14cebeSEric Cheng continue;
6203da14cebeSEric Cheng if (lstate->mi_lenable) {
6204da14cebeSEric Cheng if (!(mcip->mci_state_flags & MCIS_DESC_LOGGED)) {
6205c228408bSMichael Lim ninfo = mac_write_link_desc(mcip);
6206c228408bSMichael Lim if (ninfo == NULL) {
6207da14cebeSEric Cheng /*
6208da14cebeSEric Cheng * We can't terminate it if this is the last
6209da14cebeSEric Cheng * walk, else there might be some links with
6210da14cebeSEric Cheng * mi_desc_logged set to true, which means
6211da14cebeSEric Cheng * their description won't be logged the next
6212da14cebeSEric Cheng * time logging is started (similarly for the
6213da14cebeSEric Cheng * flows within such links). We can continue
6214da14cebeSEric Cheng * without walking the flow table (i.e. to
6215da14cebeSEric Cheng * set fe_desc_logged to false) because we
6216da14cebeSEric Cheng * won't have written any flow stuff for this
6217da14cebeSEric Cheng * link as we haven't logged the link itself.
6218da14cebeSEric Cheng */
6219c228408bSMichael Lim i_mac_perim_exit(mip);
6220da14cebeSEric Cheng if (lstate->mi_last)
6221c228408bSMichael Lim return (0);
6222da14cebeSEric Cheng else
6223c228408bSMichael Lim return (-1);
6224da14cebeSEric Cheng }
6225da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_DESC_LOGGED;
6226c228408bSMichael Lim list_insert_tail(lstate->mi_list, ninfo);
6227da14cebeSEric Cheng }
6228da14cebeSEric Cheng }
6229da14cebeSEric Cheng
6230c228408bSMichael Lim ninfo = mac_write_link_stats(mcip);
6231c228408bSMichael Lim if (ninfo == NULL && !lstate->mi_last) {
6232c228408bSMichael Lim i_mac_perim_exit(mip);
6233c228408bSMichael Lim return (-1);
6234c228408bSMichael Lim }
6235c228408bSMichael Lim list_insert_tail(lstate->mi_list, ninfo);
6236da14cebeSEric Cheng
6237da14cebeSEric Cheng if (lstate->mi_last)
6238da14cebeSEric Cheng mcip->mci_state_flags &= ~MCIS_DESC_LOGGED;
6239da14cebeSEric Cheng
6240da14cebeSEric Cheng if (lstate->mi_fenable) {
6241da14cebeSEric Cheng if (mcip->mci_subflow_tab != NULL) {
6242c228408bSMichael Lim (void) mac_flow_walk_nolock(
6243c228408bSMichael Lim mcip->mci_subflow_tab, mac_log_flowinfo,
6244c228408bSMichael Lim lstate);
6245da14cebeSEric Cheng }
6246da14cebeSEric Cheng }
6247da14cebeSEric Cheng }
6248c228408bSMichael Lim i_mac_perim_exit(mip);
6249c228408bSMichael Lim return (0);
6250c228408bSMichael Lim }
6251c228408bSMichael Lim
6252c228408bSMichael Lim /*
6253c228408bSMichael Lim * modhash walker function to add a mac_impl_t to a list
6254c228408bSMichael Lim */
6255c228408bSMichael Lim /*ARGSUSED*/
6256c228408bSMichael Lim static uint_t
i_mac_impl_list_walker(mod_hash_key_t key,mod_hash_val_t * val,void * arg)6257c228408bSMichael Lim i_mac_impl_list_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
6258c228408bSMichael Lim {
6259c228408bSMichael Lim list_t *list = (list_t *)arg;
6260c228408bSMichael Lim mac_impl_t *mip = (mac_impl_t *)val;
6261c228408bSMichael Lim
6262c228408bSMichael Lim if ((mip->mi_state_flags & MIS_DISABLED) == 0) {
6263c228408bSMichael Lim list_insert_tail(list, mip);
6264c228408bSMichael Lim mip->mi_ref++;
6265c228408bSMichael Lim }
6266c228408bSMichael Lim
6267da14cebeSEric Cheng return (MH_WALK_CONTINUE);
6268da14cebeSEric Cheng }
6269da14cebeSEric Cheng
6270c228408bSMichael Lim void
i_mac_log_info(list_t * net_log_list,i_mac_log_state_t * lstate)6271c228408bSMichael Lim i_mac_log_info(list_t *net_log_list, i_mac_log_state_t *lstate)
6272c228408bSMichael Lim {
6273c228408bSMichael Lim list_t mac_impl_list;
6274c228408bSMichael Lim mac_impl_t *mip;
6275c228408bSMichael Lim netinfo_t *ninfo;
6276c228408bSMichael Lim
6277c228408bSMichael Lim /* Create list of mac_impls */
6278c228408bSMichael Lim ASSERT(RW_LOCK_HELD(&i_mac_impl_lock));
6279c228408bSMichael Lim list_create(&mac_impl_list, sizeof (mac_impl_t), offsetof(mac_impl_t,
6280c228408bSMichael Lim mi_node));
6281c228408bSMichael Lim mod_hash_walk(i_mac_impl_hash, i_mac_impl_list_walker, &mac_impl_list);
6282c228408bSMichael Lim rw_exit(&i_mac_impl_lock);
6283c228408bSMichael Lim
6284c228408bSMichael Lim /* Create log entries for each mac_impl */
6285c228408bSMichael Lim for (mip = list_head(&mac_impl_list); mip != NULL;
6286c228408bSMichael Lim mip = list_next(&mac_impl_list, mip)) {
6287c228408bSMichael Lim if (i_mac_impl_log(mip, lstate) != 0)
6288c228408bSMichael Lim continue;
6289c228408bSMichael Lim }
6290c228408bSMichael Lim
6291c228408bSMichael Lim /* Remove elements and destroy list of mac_impls */
6292c228408bSMichael Lim rw_enter(&i_mac_impl_lock, RW_WRITER);
6293c228408bSMichael Lim while ((mip = list_remove_tail(&mac_impl_list)) != NULL) {
6294c228408bSMichael Lim mip->mi_ref--;
6295c228408bSMichael Lim }
6296c228408bSMichael Lim rw_exit(&i_mac_impl_lock);
6297c228408bSMichael Lim list_destroy(&mac_impl_list);
6298c228408bSMichael Lim
6299c228408bSMichael Lim /*
6300c228408bSMichael Lim * Write log entries to files outside of locks, free associated
6301c228408bSMichael Lim * structures, and remove entries from the list.
6302c228408bSMichael Lim */
6303c228408bSMichael Lim while ((ninfo = list_head(net_log_list)) != NULL) {
6304c228408bSMichael Lim (void) exacct_commit_netinfo(ninfo->ni_record, ninfo->ni_type);
6305c228408bSMichael Lim list_remove(net_log_list, ninfo);
6306c228408bSMichael Lim kmem_free(ninfo->ni_record, ninfo->ni_size);
6307c228408bSMichael Lim kmem_free(ninfo, sizeof (*ninfo));
6308c228408bSMichael Lim }
6309c228408bSMichael Lim list_destroy(net_log_list);
6310c228408bSMichael Lim }
6311c228408bSMichael Lim
6312da14cebeSEric Cheng /*
6313da14cebeSEric Cheng * The timer thread that runs every mac_logging_interval seconds and logs
6314da14cebeSEric Cheng * link and/or flow information.
6315da14cebeSEric Cheng */
6316da14cebeSEric Cheng /* ARGSUSED */
6317da14cebeSEric Cheng void
mac_log_linkinfo(void * arg)6318da14cebeSEric Cheng mac_log_linkinfo(void *arg)
6319da14cebeSEric Cheng {
6320da14cebeSEric Cheng i_mac_log_state_t lstate;
6321c228408bSMichael Lim list_t net_log_list;
6322c228408bSMichael Lim
6323c228408bSMichael Lim list_create(&net_log_list, sizeof (netinfo_t),
6324c228408bSMichael Lim offsetof(netinfo_t, ni_link));
6325da14cebeSEric Cheng
6326da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_READER);
6327da14cebeSEric Cheng if (!mac_flow_log_enable && !mac_link_log_enable) {
6328da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
6329da14cebeSEric Cheng return;
6330da14cebeSEric Cheng }
6331da14cebeSEric Cheng lstate.mi_fenable = mac_flow_log_enable;
6332da14cebeSEric Cheng lstate.mi_lenable = mac_link_log_enable;
6333da14cebeSEric Cheng lstate.mi_last = B_FALSE;
6334c228408bSMichael Lim lstate.mi_list = &net_log_list;
6335da14cebeSEric Cheng
6336c228408bSMichael Lim /* Write log entries for each mac_impl in the list */
6337c228408bSMichael Lim i_mac_log_info(&net_log_list, &lstate);
6338da14cebeSEric Cheng
6339da14cebeSEric Cheng if (mac_flow_log_enable || mac_link_log_enable) {
6340da14cebeSEric Cheng mac_logging_timer = timeout(mac_log_linkinfo, NULL,
6341da14cebeSEric Cheng SEC_TO_TICK(mac_logging_interval));
6342da14cebeSEric Cheng }
6343da14cebeSEric Cheng }
6344da14cebeSEric Cheng
63455d460eafSCathy Zhou typedef struct i_mac_fastpath_state_s {
63465d460eafSCathy Zhou boolean_t mf_disable;
63475d460eafSCathy Zhou int mf_err;
63485d460eafSCathy Zhou } i_mac_fastpath_state_t;
63495d460eafSCathy Zhou
6350c228408bSMichael Lim /* modhash walker function to enable or disable fastpath */
63515d460eafSCathy Zhou /*ARGSUSED*/
63525d460eafSCathy Zhou static uint_t
i_mac_fastpath_walker(mod_hash_key_t key,mod_hash_val_t * val,void * arg)6353c228408bSMichael Lim i_mac_fastpath_walker(mod_hash_key_t key, mod_hash_val_t *val,
63545d460eafSCathy Zhou void *arg)
63555d460eafSCathy Zhou {
63565d460eafSCathy Zhou i_mac_fastpath_state_t *state = arg;
63575d460eafSCathy Zhou mac_handle_t mh = (mac_handle_t)val;
63585d460eafSCathy Zhou
63595d460eafSCathy Zhou if (state->mf_disable)
63605d460eafSCathy Zhou state->mf_err = mac_fastpath_disable(mh);
63615d460eafSCathy Zhou else
63625d460eafSCathy Zhou mac_fastpath_enable(mh);
63635d460eafSCathy Zhou
63645d460eafSCathy Zhou return (state->mf_err == 0 ? MH_WALK_CONTINUE : MH_WALK_TERMINATE);
63655d460eafSCathy Zhou }
63665d460eafSCathy Zhou
6367da14cebeSEric Cheng /*
6368da14cebeSEric Cheng * Start the logging timer.
6369da14cebeSEric Cheng */
63705d460eafSCathy Zhou int
mac_start_logusage(mac_logtype_t type,uint_t interval)6371da14cebeSEric Cheng mac_start_logusage(mac_logtype_t type, uint_t interval)
6372da14cebeSEric Cheng {
6373c228408bSMichael Lim i_mac_fastpath_state_t dstate = {B_TRUE, 0};
6374c228408bSMichael Lim i_mac_fastpath_state_t estate = {B_FALSE, 0};
63755d460eafSCathy Zhou int err;
63765d460eafSCathy Zhou
6377da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_WRITER);
6378da14cebeSEric Cheng switch (type) {
6379da14cebeSEric Cheng case MAC_LOGTYPE_FLOW:
6380da14cebeSEric Cheng if (mac_flow_log_enable) {
6381da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
63825d460eafSCathy Zhou return (0);
6383da14cebeSEric Cheng }
6384da14cebeSEric Cheng /* FALLTHRU */
6385da14cebeSEric Cheng case MAC_LOGTYPE_LINK:
6386da14cebeSEric Cheng if (mac_link_log_enable) {
6387da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
63885d460eafSCathy Zhou return (0);
6389da14cebeSEric Cheng }
6390da14cebeSEric Cheng break;
6391da14cebeSEric Cheng default:
6392da14cebeSEric Cheng ASSERT(0);
6393da14cebeSEric Cheng }
63945d460eafSCathy Zhou
63955d460eafSCathy Zhou /* Disable fastpath */
6396c228408bSMichael Lim mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &dstate);
6397c228408bSMichael Lim if ((err = dstate.mf_err) != 0) {
63985d460eafSCathy Zhou /* Reenable fastpath */
6399c228408bSMichael Lim mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &estate);
64005d460eafSCathy Zhou rw_exit(&i_mac_impl_lock);
64015d460eafSCathy Zhou return (err);
64025d460eafSCathy Zhou }
64035d460eafSCathy Zhou
64045d460eafSCathy Zhou switch (type) {
64055d460eafSCathy Zhou case MAC_LOGTYPE_FLOW:
64065d460eafSCathy Zhou mac_flow_log_enable = B_TRUE;
64075d460eafSCathy Zhou /* FALLTHRU */
64085d460eafSCathy Zhou case MAC_LOGTYPE_LINK:
64095d460eafSCathy Zhou mac_link_log_enable = B_TRUE;
64105d460eafSCathy Zhou break;
64115d460eafSCathy Zhou }
64125d460eafSCathy Zhou
6413da14cebeSEric Cheng mac_logging_interval = interval;
6414da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
6415da14cebeSEric Cheng mac_log_linkinfo(NULL);
64165d460eafSCathy Zhou return (0);
6417da14cebeSEric Cheng }
6418da14cebeSEric Cheng
6419da14cebeSEric Cheng /*
6420c228408bSMichael Lim * Stop the logging timer if both link and flow logging are turned off.
6421da14cebeSEric Cheng */
6422da14cebeSEric Cheng void
mac_stop_logusage(mac_logtype_t type)6423da14cebeSEric Cheng mac_stop_logusage(mac_logtype_t type)
6424da14cebeSEric Cheng {
6425da14cebeSEric Cheng i_mac_log_state_t lstate;
6426c228408bSMichael Lim i_mac_fastpath_state_t estate = {B_FALSE, 0};
6427c228408bSMichael Lim list_t net_log_list;
6428c228408bSMichael Lim
6429c228408bSMichael Lim list_create(&net_log_list, sizeof (netinfo_t),
6430c228408bSMichael Lim offsetof(netinfo_t, ni_link));
6431da14cebeSEric Cheng
6432da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_WRITER);
6433c228408bSMichael Lim
6434da14cebeSEric Cheng lstate.mi_fenable = mac_flow_log_enable;
6435da14cebeSEric Cheng lstate.mi_lenable = mac_link_log_enable;
6436c228408bSMichael Lim lstate.mi_list = &net_log_list;
6437da14cebeSEric Cheng
6438da14cebeSEric Cheng /* Last walk */
6439da14cebeSEric Cheng lstate.mi_last = B_TRUE;
6440da14cebeSEric Cheng
6441da14cebeSEric Cheng switch (type) {
6442da14cebeSEric Cheng case MAC_LOGTYPE_FLOW:
6443da14cebeSEric Cheng if (lstate.mi_fenable) {
6444da14cebeSEric Cheng ASSERT(mac_link_log_enable);
6445da14cebeSEric Cheng mac_flow_log_enable = B_FALSE;
6446da14cebeSEric Cheng mac_link_log_enable = B_FALSE;
6447da14cebeSEric Cheng break;
6448da14cebeSEric Cheng }
6449da14cebeSEric Cheng /* FALLTHRU */
6450da14cebeSEric Cheng case MAC_LOGTYPE_LINK:
6451da14cebeSEric Cheng if (!lstate.mi_lenable || mac_flow_log_enable) {
6452da14cebeSEric Cheng rw_exit(&i_mac_impl_lock);
6453da14cebeSEric Cheng return;
6454da14cebeSEric Cheng }
6455da14cebeSEric Cheng mac_link_log_enable = B_FALSE;
6456da14cebeSEric Cheng break;
6457da14cebeSEric Cheng default:
6458da14cebeSEric Cheng ASSERT(0);
6459da14cebeSEric Cheng }
64605d460eafSCathy Zhou
64615d460eafSCathy Zhou /* Reenable fastpath */
6462c228408bSMichael Lim mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &estate);
64635d460eafSCathy Zhou
6464da14cebeSEric Cheng (void) untimeout(mac_logging_timer);
646584de666eSRyan Zezeski mac_logging_timer = NULL;
6466da14cebeSEric Cheng
6467c228408bSMichael Lim /* Write log entries for each mac_impl in the list */
6468c228408bSMichael Lim i_mac_log_info(&net_log_list, &lstate);
6469da14cebeSEric Cheng }
6470da14cebeSEric Cheng
6471da14cebeSEric Cheng /*
6472da14cebeSEric Cheng * Walk the rx and tx SRS/SRs for a flow and update the priority value.
6473da14cebeSEric Cheng */
6474da14cebeSEric Cheng void
mac_flow_update_priority(mac_client_impl_t * mcip,flow_entry_t * flent)6475da14cebeSEric Cheng mac_flow_update_priority(mac_client_impl_t *mcip, flow_entry_t *flent)
6476da14cebeSEric Cheng {
6477da14cebeSEric Cheng pri_t pri;
6478da14cebeSEric Cheng int count;
6479da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs;
6480da14cebeSEric Cheng
6481da14cebeSEric Cheng if (flent->fe_rx_srs_cnt <= 0)
6482da14cebeSEric Cheng return;
6483da14cebeSEric Cheng
6484da14cebeSEric Cheng if (((mac_soft_ring_set_t *)flent->fe_rx_srs[0])->srs_type ==
6485da14cebeSEric Cheng SRST_FLOW) {
6486da14cebeSEric Cheng pri = FLOW_PRIORITY(mcip->mci_min_pri,
6487da14cebeSEric Cheng mcip->mci_max_pri,
6488da14cebeSEric Cheng flent->fe_resource_props.mrp_priority);
6489da14cebeSEric Cheng } else {
6490da14cebeSEric Cheng pri = mcip->mci_max_pri;
6491da14cebeSEric Cheng }
6492da14cebeSEric Cheng
6493da14cebeSEric Cheng for (count = 0; count < flent->fe_rx_srs_cnt; count++) {
6494da14cebeSEric Cheng mac_srs = flent->fe_rx_srs[count];
6495da14cebeSEric Cheng mac_update_srs_priority(mac_srs, pri);
6496da14cebeSEric Cheng }
6497da14cebeSEric Cheng /*
6498da14cebeSEric Cheng * If we have a Tx SRS, we need to modify all the threads associated
6499da14cebeSEric Cheng * with it.
6500da14cebeSEric Cheng */
6501da14cebeSEric Cheng if (flent->fe_tx_srs != NULL)
6502da14cebeSEric Cheng mac_update_srs_priority(flent->fe_tx_srs, pri);
6503da14cebeSEric Cheng }
6504da14cebeSEric Cheng
6505da14cebeSEric Cheng /*
6506da14cebeSEric Cheng * RX and TX rings are reserved according to different semantics depending
6507da14cebeSEric Cheng * on the requests from the MAC clients and type of rings:
6508da14cebeSEric Cheng *
6509da14cebeSEric Cheng * On the Tx side, by default we reserve individual rings, independently from
6510da14cebeSEric Cheng * the groups.
6511da14cebeSEric Cheng *
6512da14cebeSEric Cheng * On the Rx side, the reservation is at the granularity of the group
6513da14cebeSEric Cheng * of rings, and used for v12n level 1 only. It has a special case for the
6514da14cebeSEric Cheng * primary client.
6515da14cebeSEric Cheng *
6516da14cebeSEric Cheng * If a share is allocated to a MAC client, we allocate a TX group and an
6517da14cebeSEric Cheng * RX group to the client, and assign TX rings and RX rings to these
6518da14cebeSEric Cheng * groups according to information gathered from the driver through
6519da14cebeSEric Cheng * the share capability.
6520da14cebeSEric Cheng *
6521da14cebeSEric Cheng * The foreseable evolution of Rx rings will handle v12n level 2 and higher
6522da14cebeSEric Cheng * to allocate individual rings out of a group and program the hw classifier
6523da14cebeSEric Cheng * based on IP address or higher level criteria.
6524da14cebeSEric Cheng */
6525da14cebeSEric Cheng
6526da14cebeSEric Cheng /*
6527da14cebeSEric Cheng * mac_reserve_tx_ring()
6528da14cebeSEric Cheng * Reserve a unused ring by marking it with MR_INUSE state.
6529da14cebeSEric Cheng * As reserved, the ring is ready to function.
6530da14cebeSEric Cheng *
6531da14cebeSEric Cheng * Notes for Hybrid I/O:
6532da14cebeSEric Cheng *
6533da14cebeSEric Cheng * If a specific ring is needed, it is specified through the desired_ring
6534da14cebeSEric Cheng * argument. Otherwise that argument is set to NULL.
6535da14cebeSEric Cheng * If the desired ring was previous allocated to another client, this
6536da14cebeSEric Cheng * function swaps it with a new ring from the group of unassigned rings.
6537da14cebeSEric Cheng */
6538da14cebeSEric Cheng mac_ring_t *
mac_reserve_tx_ring(mac_impl_t * mip,mac_ring_t * desired_ring)6539da14cebeSEric Cheng mac_reserve_tx_ring(mac_impl_t *mip, mac_ring_t *desired_ring)
6540da14cebeSEric Cheng {
6541da14cebeSEric Cheng mac_group_t *group;
65420dc2366fSVenugopal Iyer mac_grp_client_t *mgcp;
65430dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
65440dc2366fSVenugopal Iyer mac_soft_ring_set_t *srs;
6545da14cebeSEric Cheng
6546da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
6547da14cebeSEric Cheng
6548da14cebeSEric Cheng /*
6549da14cebeSEric Cheng * Find an available ring and start it before changing its status.
6550da14cebeSEric Cheng * The unassigned rings are at the end of the mi_tx_groups
6551da14cebeSEric Cheng * array.
6552da14cebeSEric Cheng */
65530dc2366fSVenugopal Iyer group = MAC_DEFAULT_TX_GROUP(mip);
6554da14cebeSEric Cheng
65550dc2366fSVenugopal Iyer /* Can't take the default ring out of the default group */
65560dc2366fSVenugopal Iyer ASSERT(desired_ring != (mac_ring_t *)mip->mi_default_tx_ring);
65570dc2366fSVenugopal Iyer
65580dc2366fSVenugopal Iyer if (desired_ring->mr_state == MR_FREE) {
65590dc2366fSVenugopal Iyer ASSERT(MAC_GROUP_NO_CLIENT(group));
65600dc2366fSVenugopal Iyer if (mac_start_ring(desired_ring) != 0)
65610dc2366fSVenugopal Iyer return (NULL);
65620dc2366fSVenugopal Iyer return (desired_ring);
65630dc2366fSVenugopal Iyer }
65640dc2366fSVenugopal Iyer /*
65650dc2366fSVenugopal Iyer * There are clients using this ring, so let's move the clients
65660dc2366fSVenugopal Iyer * away from using this ring.
65670dc2366fSVenugopal Iyer */
65680dc2366fSVenugopal Iyer for (mgcp = group->mrg_clients; mgcp != NULL; mgcp = mgcp->mgc_next) {
65690dc2366fSVenugopal Iyer mcip = mgcp->mgc_client;
65700dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
65710dc2366fSVenugopal Iyer srs = MCIP_TX_SRS(mcip);
65720dc2366fSVenugopal Iyer ASSERT(mac_tx_srs_ring_present(srs, desired_ring));
65730dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip,
65740dc2366fSVenugopal Iyer (mac_tx_cookie_t)mac_tx_srs_get_soft_ring(srs,
65750dc2366fSVenugopal Iyer desired_ring));
65760dc2366fSVenugopal Iyer mac_tx_srs_del_ring(srs, desired_ring);
65770dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
65780dc2366fSVenugopal Iyer }
65790dc2366fSVenugopal Iyer return (desired_ring);
65800dc2366fSVenugopal Iyer }
65810dc2366fSVenugopal Iyer
65820dc2366fSVenugopal Iyer /*
658384de666eSRyan Zezeski * For a non-default group with multiple clients, return the primary client.
65840dc2366fSVenugopal Iyer */
65850dc2366fSVenugopal Iyer static mac_client_impl_t *
mac_get_grp_primary(mac_group_t * grp)65860dc2366fSVenugopal Iyer mac_get_grp_primary(mac_group_t *grp)
65870dc2366fSVenugopal Iyer {
65880dc2366fSVenugopal Iyer mac_grp_client_t *mgcp = grp->mrg_clients;
65890dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
65900dc2366fSVenugopal Iyer
65910dc2366fSVenugopal Iyer while (mgcp != NULL) {
65920dc2366fSVenugopal Iyer mcip = mgcp->mgc_client;
65930dc2366fSVenugopal Iyer if (mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC)
65940dc2366fSVenugopal Iyer return (mcip);
65950dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
65960dc2366fSVenugopal Iyer }
65970dc2366fSVenugopal Iyer return (NULL);
65980dc2366fSVenugopal Iyer }
65990dc2366fSVenugopal Iyer
66000dc2366fSVenugopal Iyer /*
66010dc2366fSVenugopal Iyer * Hybrid I/O specifies the ring that should be given to a share.
66020dc2366fSVenugopal Iyer * If the ring is already used by clients, then we need to release
66030dc2366fSVenugopal Iyer * the ring back to the default group so that we can give it to
66040dc2366fSVenugopal Iyer * the share. This means the clients using this ring now get a
66050dc2366fSVenugopal Iyer * replacement ring. If there aren't any replacement rings, this
66060dc2366fSVenugopal Iyer * function returns a failure.
66070dc2366fSVenugopal Iyer */
66080dc2366fSVenugopal Iyer static int
mac_reclaim_ring_from_grp(mac_impl_t * mip,mac_ring_type_t ring_type,mac_ring_t * ring,mac_ring_t ** rings,int nrings)66090dc2366fSVenugopal Iyer mac_reclaim_ring_from_grp(mac_impl_t *mip, mac_ring_type_t ring_type,
66100dc2366fSVenugopal Iyer mac_ring_t *ring, mac_ring_t **rings, int nrings)
66110dc2366fSVenugopal Iyer {
66120dc2366fSVenugopal Iyer mac_group_t *group = (mac_group_t *)ring->mr_gh;
66130dc2366fSVenugopal Iyer mac_resource_props_t *mrp;
66140dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
66150dc2366fSVenugopal Iyer mac_group_t *defgrp;
66160dc2366fSVenugopal Iyer mac_ring_t *tring;
66170dc2366fSVenugopal Iyer mac_group_t *tgrp;
66180dc2366fSVenugopal Iyer int i;
66190dc2366fSVenugopal Iyer int j;
66200dc2366fSVenugopal Iyer
66210dc2366fSVenugopal Iyer mcip = MAC_GROUP_ONLY_CLIENT(group);
66220dc2366fSVenugopal Iyer if (mcip == NULL)
66230dc2366fSVenugopal Iyer mcip = mac_get_grp_primary(group);
66240dc2366fSVenugopal Iyer ASSERT(mcip != NULL);
66256895f6f4SToomas Soome ASSERT(mcip->mci_share == 0);
66260dc2366fSVenugopal Iyer
66270dc2366fSVenugopal Iyer mrp = MCIP_RESOURCE_PROPS(mcip);
66280dc2366fSVenugopal Iyer if (ring_type == MAC_RING_TYPE_RX) {
66290dc2366fSVenugopal Iyer defgrp = mip->mi_rx_donor_grp;
66300dc2366fSVenugopal Iyer if ((mrp->mrp_mask & MRP_RX_RINGS) == 0) {
66310dc2366fSVenugopal Iyer /* Need to put this mac client in the default group */
66320dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, group, defgrp) != 0)
66330dc2366fSVenugopal Iyer return (ENOSPC);
6634da14cebeSEric Cheng } else {
66350dc2366fSVenugopal Iyer /*
66360dc2366fSVenugopal Iyer * Switch this ring with some other ring from
66370dc2366fSVenugopal Iyer * the default group.
66380dc2366fSVenugopal Iyer */
66390dc2366fSVenugopal Iyer for (tring = defgrp->mrg_rings; tring != NULL;
66400dc2366fSVenugopal Iyer tring = tring->mr_next) {
66410dc2366fSVenugopal Iyer if (tring->mr_index == 0)
6642da14cebeSEric Cheng continue;
66430dc2366fSVenugopal Iyer for (j = 0; j < nrings; j++) {
66440dc2366fSVenugopal Iyer if (rings[j] == tring)
6645da14cebeSEric Cheng break;
6646da14cebeSEric Cheng }
66470dc2366fSVenugopal Iyer if (j >= nrings)
664808ac1c49SNicolas Droux break;
664908ac1c49SNicolas Droux }
66500dc2366fSVenugopal Iyer if (tring == NULL)
66510dc2366fSVenugopal Iyer return (ENOSPC);
66520dc2366fSVenugopal Iyer if (mac_group_mov_ring(mip, group, tring) != 0)
66530dc2366fSVenugopal Iyer return (ENOSPC);
66540dc2366fSVenugopal Iyer if (mac_group_mov_ring(mip, defgrp, ring) != 0) {
66550dc2366fSVenugopal Iyer (void) mac_group_mov_ring(mip, defgrp, tring);
66560dc2366fSVenugopal Iyer return (ENOSPC);
66570dc2366fSVenugopal Iyer }
66580dc2366fSVenugopal Iyer }
66590dc2366fSVenugopal Iyer ASSERT(ring->mr_gh == (mac_group_handle_t)defgrp);
66600dc2366fSVenugopal Iyer return (0);
66610dc2366fSVenugopal Iyer }
6662da14cebeSEric Cheng
66630dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
66640dc2366fSVenugopal Iyer if (ring == (mac_ring_t *)mip->mi_default_tx_ring) {
6665da14cebeSEric Cheng /*
66660dc2366fSVenugopal Iyer * See if we can get a spare ring to replace the default
6667da14cebeSEric Cheng * ring.
6668da14cebeSEric Cheng */
66690dc2366fSVenugopal Iyer if (defgrp->mrg_cur_count == 1) {
667008ac1c49SNicolas Droux /*
66710dc2366fSVenugopal Iyer * Need to get a ring from another client, see if
66720dc2366fSVenugopal Iyer * there are any clients that can be moved to
66730dc2366fSVenugopal Iyer * the default group, thereby freeing some rings.
667408ac1c49SNicolas Droux */
66750dc2366fSVenugopal Iyer for (i = 0; i < mip->mi_tx_group_count; i++) {
66760dc2366fSVenugopal Iyer tgrp = &mip->mi_tx_groups[i];
66770dc2366fSVenugopal Iyer if (tgrp->mrg_state ==
66780dc2366fSVenugopal Iyer MAC_GROUP_STATE_REGISTERED) {
66790dc2366fSVenugopal Iyer continue;
66800dc2366fSVenugopal Iyer }
66810dc2366fSVenugopal Iyer mcip = MAC_GROUP_ONLY_CLIENT(tgrp);
66820dc2366fSVenugopal Iyer if (mcip == NULL)
66830dc2366fSVenugopal Iyer mcip = mac_get_grp_primary(tgrp);
66840dc2366fSVenugopal Iyer ASSERT(mcip != NULL);
66850dc2366fSVenugopal Iyer mrp = MCIP_RESOURCE_PROPS(mcip);
66860dc2366fSVenugopal Iyer if ((mrp->mrp_mask & MRP_TX_RINGS) == 0) {
66870dc2366fSVenugopal Iyer ASSERT(tgrp->mrg_cur_count == 1);
668808ac1c49SNicolas Droux /*
66890dc2366fSVenugopal Iyer * If this ring is part of the
66900dc2366fSVenugopal Iyer * rings asked by the share we cannot
66910dc2366fSVenugopal Iyer * use it as the default ring.
669208ac1c49SNicolas Droux */
66930dc2366fSVenugopal Iyer for (j = 0; j < nrings; j++) {
66940dc2366fSVenugopal Iyer if (rings[j] == tgrp->mrg_rings)
66950dc2366fSVenugopal Iyer break;
669608ac1c49SNicolas Droux }
66970dc2366fSVenugopal Iyer if (j < nrings)
66980dc2366fSVenugopal Iyer continue;
66990dc2366fSVenugopal Iyer mac_tx_client_quiesce(
67000dc2366fSVenugopal Iyer (mac_client_handle_t)mcip);
67010dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, tgrp,
67020dc2366fSVenugopal Iyer defgrp);
67030dc2366fSVenugopal Iyer mac_tx_client_restart(
67040dc2366fSVenugopal Iyer (mac_client_handle_t)mcip);
6705da14cebeSEric Cheng break;
6706da14cebeSEric Cheng }
6707da14cebeSEric Cheng }
6708da14cebeSEric Cheng /*
67090dc2366fSVenugopal Iyer * All the rings are reserved, can't give up the
67100dc2366fSVenugopal Iyer * default ring.
6711da14cebeSEric Cheng */
67120dc2366fSVenugopal Iyer if (defgrp->mrg_cur_count <= 1)
67130dc2366fSVenugopal Iyer return (ENOSPC);
67140dc2366fSVenugopal Iyer }
67150dc2366fSVenugopal Iyer /*
67160dc2366fSVenugopal Iyer * Swap the default ring with another.
67170dc2366fSVenugopal Iyer */
67180dc2366fSVenugopal Iyer for (tring = defgrp->mrg_rings; tring != NULL;
67190dc2366fSVenugopal Iyer tring = tring->mr_next) {
67200dc2366fSVenugopal Iyer /*
67210dc2366fSVenugopal Iyer * If this ring is part of the rings asked by the
67220dc2366fSVenugopal Iyer * share we cannot use it as the default ring.
67230dc2366fSVenugopal Iyer */
67240dc2366fSVenugopal Iyer for (j = 0; j < nrings; j++) {
67250dc2366fSVenugopal Iyer if (rings[j] == tring)
67260dc2366fSVenugopal Iyer break;
67270dc2366fSVenugopal Iyer }
67280dc2366fSVenugopal Iyer if (j >= nrings)
67290dc2366fSVenugopal Iyer break;
67300dc2366fSVenugopal Iyer }
67310dc2366fSVenugopal Iyer ASSERT(tring != NULL);
67320dc2366fSVenugopal Iyer mip->mi_default_tx_ring = (mac_ring_handle_t)tring;
67330dc2366fSVenugopal Iyer return (0);
67340dc2366fSVenugopal Iyer }
67350dc2366fSVenugopal Iyer /*
67360dc2366fSVenugopal Iyer * The Tx ring is with a group reserved by a MAC client. See if
67370dc2366fSVenugopal Iyer * we can swap it.
67380dc2366fSVenugopal Iyer */
67390dc2366fSVenugopal Iyer ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED);
67400dc2366fSVenugopal Iyer mcip = MAC_GROUP_ONLY_CLIENT(group);
67410dc2366fSVenugopal Iyer if (mcip == NULL)
67420dc2366fSVenugopal Iyer mcip = mac_get_grp_primary(group);
67430dc2366fSVenugopal Iyer ASSERT(mcip != NULL);
67440dc2366fSVenugopal Iyer mrp = MCIP_RESOURCE_PROPS(mcip);
67450dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip);
67460dc2366fSVenugopal Iyer if ((mrp->mrp_mask & MRP_TX_RINGS) == 0) {
67470dc2366fSVenugopal Iyer ASSERT(group->mrg_cur_count == 1);
67480dc2366fSVenugopal Iyer /* Put this mac client in the default group */
67490dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, group, defgrp);
67500dc2366fSVenugopal Iyer } else {
67510dc2366fSVenugopal Iyer /*
67520dc2366fSVenugopal Iyer * Switch this ring with some other ring from
67530dc2366fSVenugopal Iyer * the default group.
67540dc2366fSVenugopal Iyer */
67550dc2366fSVenugopal Iyer for (tring = defgrp->mrg_rings; tring != NULL;
67560dc2366fSVenugopal Iyer tring = tring->mr_next) {
67570dc2366fSVenugopal Iyer if (tring == (mac_ring_t *)mip->mi_default_tx_ring)
67580dc2366fSVenugopal Iyer continue;
67590dc2366fSVenugopal Iyer /*
67600dc2366fSVenugopal Iyer * If this ring is part of the rings asked by the
67610dc2366fSVenugopal Iyer * share we cannot use it for swapping.
67620dc2366fSVenugopal Iyer */
67630dc2366fSVenugopal Iyer for (j = 0; j < nrings; j++) {
67640dc2366fSVenugopal Iyer if (rings[j] == tring)
67650dc2366fSVenugopal Iyer break;
67660dc2366fSVenugopal Iyer }
67670dc2366fSVenugopal Iyer if (j >= nrings)
67680dc2366fSVenugopal Iyer break;
67690dc2366fSVenugopal Iyer }
67700dc2366fSVenugopal Iyer if (tring == NULL) {
67710dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
67720dc2366fSVenugopal Iyer return (ENOSPC);
67730dc2366fSVenugopal Iyer }
67740dc2366fSVenugopal Iyer if (mac_group_mov_ring(mip, group, tring) != 0) {
67750dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
67760dc2366fSVenugopal Iyer return (ENOSPC);
67770dc2366fSVenugopal Iyer }
67780dc2366fSVenugopal Iyer if (mac_group_mov_ring(mip, defgrp, ring) != 0) {
67790dc2366fSVenugopal Iyer (void) mac_group_mov_ring(mip, defgrp, tring);
67800dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
67810dc2366fSVenugopal Iyer return (ENOSPC);
67820dc2366fSVenugopal Iyer }
67830dc2366fSVenugopal Iyer }
67840dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip);
67850dc2366fSVenugopal Iyer ASSERT(ring->mr_gh == (mac_group_handle_t)defgrp);
67860dc2366fSVenugopal Iyer return (0);
67870dc2366fSVenugopal Iyer }
6788da14cebeSEric Cheng
6789da14cebeSEric Cheng /*
6790da14cebeSEric Cheng * Populate a zero-ring group with rings. If the share is non-NULL,
6791da14cebeSEric Cheng * the rings are chosen according to that share.
6792da14cebeSEric Cheng * Invoked after allocating a new RX or TX group through
6793da14cebeSEric Cheng * mac_reserve_rx_group() or mac_reserve_tx_group(), respectively.
6794da14cebeSEric Cheng * Returns zero on success, an errno otherwise.
6795da14cebeSEric Cheng */
6796da14cebeSEric Cheng int
i_mac_group_allocate_rings(mac_impl_t * mip,mac_ring_type_t ring_type,mac_group_t * src_group,mac_group_t * new_group,mac_share_handle_t share,uint32_t ringcnt)6797da14cebeSEric Cheng i_mac_group_allocate_rings(mac_impl_t *mip, mac_ring_type_t ring_type,
67980dc2366fSVenugopal Iyer mac_group_t *src_group, mac_group_t *new_group, mac_share_handle_t share,
67990dc2366fSVenugopal Iyer uint32_t ringcnt)
6800da14cebeSEric Cheng {
68010dc2366fSVenugopal Iyer mac_ring_t **rings, *ring;
6802da14cebeSEric Cheng uint_t nrings;
68030dc2366fSVenugopal Iyer int rv = 0, i = 0, j;
6804da14cebeSEric Cheng
68050dc2366fSVenugopal Iyer ASSERT((ring_type == MAC_RING_TYPE_RX &&
68060dc2366fSVenugopal Iyer mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) ||
68070dc2366fSVenugopal Iyer (ring_type == MAC_RING_TYPE_TX &&
68080dc2366fSVenugopal Iyer mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC));
6809da14cebeSEric Cheng
6810da14cebeSEric Cheng /*
6811da14cebeSEric Cheng * First find the rings to allocate to the group.
6812da14cebeSEric Cheng */
681336f99a58SToomas Soome if (share != 0) {
6814da14cebeSEric Cheng /* get rings through ms_squery() */
6815da14cebeSEric Cheng mip->mi_share_capab.ms_squery(share, ring_type, NULL, &nrings);
6816da14cebeSEric Cheng ASSERT(nrings != 0);
6817da14cebeSEric Cheng rings = kmem_alloc(nrings * sizeof (mac_ring_handle_t),
6818da14cebeSEric Cheng KM_SLEEP);
6819da14cebeSEric Cheng mip->mi_share_capab.ms_squery(share, ring_type,
6820da14cebeSEric Cheng (mac_ring_handle_t *)rings, &nrings);
68210dc2366fSVenugopal Iyer for (i = 0; i < nrings; i++) {
68220dc2366fSVenugopal Iyer /*
68230dc2366fSVenugopal Iyer * If we have given this ring to a non-default
68240dc2366fSVenugopal Iyer * group, we need to check if we can get this
68250dc2366fSVenugopal Iyer * ring.
68260dc2366fSVenugopal Iyer */
68270dc2366fSVenugopal Iyer ring = rings[i];
68280dc2366fSVenugopal Iyer if (ring->mr_gh != (mac_group_handle_t)src_group ||
68290dc2366fSVenugopal Iyer ring == (mac_ring_t *)mip->mi_default_tx_ring) {
68300dc2366fSVenugopal Iyer if (mac_reclaim_ring_from_grp(mip, ring_type,
68310dc2366fSVenugopal Iyer ring, rings, nrings) != 0) {
68320dc2366fSVenugopal Iyer rv = ENOSPC;
68330dc2366fSVenugopal Iyer goto bail;
68340dc2366fSVenugopal Iyer }
68350dc2366fSVenugopal Iyer }
68360dc2366fSVenugopal Iyer }
6837da14cebeSEric Cheng } else {
6838da14cebeSEric Cheng /*
6839da14cebeSEric Cheng * Pick one ring from default group.
6840da14cebeSEric Cheng *
6841da14cebeSEric Cheng * for now pick the second ring which requires the first ring
6842da14cebeSEric Cheng * at index 0 to stay in the default group, since it is the
6843da14cebeSEric Cheng * ring which carries the multicast traffic.
6844da14cebeSEric Cheng * We need a better way for a driver to indicate this,
6845da14cebeSEric Cheng * for example a per-ring flag.
6846da14cebeSEric Cheng */
68470dc2366fSVenugopal Iyer rings = kmem_alloc(ringcnt * sizeof (mac_ring_handle_t),
68480dc2366fSVenugopal Iyer KM_SLEEP);
6849da14cebeSEric Cheng for (ring = src_group->mrg_rings; ring != NULL;
6850da14cebeSEric Cheng ring = ring->mr_next) {
68510dc2366fSVenugopal Iyer if (ring_type == MAC_RING_TYPE_RX &&
68520dc2366fSVenugopal Iyer ring->mr_index == 0) {
68530dc2366fSVenugopal Iyer continue;
68540dc2366fSVenugopal Iyer }
68550dc2366fSVenugopal Iyer if (ring_type == MAC_RING_TYPE_TX &&
68560dc2366fSVenugopal Iyer ring == (mac_ring_t *)mip->mi_default_tx_ring) {
68570dc2366fSVenugopal Iyer continue;
68580dc2366fSVenugopal Iyer }
68590dc2366fSVenugopal Iyer rings[i++] = ring;
68600dc2366fSVenugopal Iyer if (i == ringcnt)
6861da14cebeSEric Cheng break;
6862da14cebeSEric Cheng }
6863da14cebeSEric Cheng ASSERT(ring != NULL);
68640dc2366fSVenugopal Iyer nrings = i;
68650dc2366fSVenugopal Iyer /* Not enough rings as required */
68660dc2366fSVenugopal Iyer if (nrings != ringcnt) {
68670dc2366fSVenugopal Iyer rv = ENOSPC;
68680dc2366fSVenugopal Iyer goto bail;
68690dc2366fSVenugopal Iyer }
6870da14cebeSEric Cheng }
6871da14cebeSEric Cheng
6872da14cebeSEric Cheng switch (ring_type) {
6873da14cebeSEric Cheng case MAC_RING_TYPE_RX:
68740dc2366fSVenugopal Iyer if (src_group->mrg_cur_count - nrings < 1) {
6875da14cebeSEric Cheng /* we ran out of rings */
68760dc2366fSVenugopal Iyer rv = ENOSPC;
68770dc2366fSVenugopal Iyer goto bail;
6878da14cebeSEric Cheng }
6879da14cebeSEric Cheng
6880da14cebeSEric Cheng /* move receive rings to new group */
6881da14cebeSEric Cheng for (i = 0; i < nrings; i++) {
6882da14cebeSEric Cheng rv = mac_group_mov_ring(mip, new_group, rings[i]);
6883da14cebeSEric Cheng if (rv != 0) {
6884da14cebeSEric Cheng /* move rings back on failure */
6885da14cebeSEric Cheng for (j = 0; j < i; j++) {
6886da14cebeSEric Cheng (void) mac_group_mov_ring(mip,
6887da14cebeSEric Cheng src_group, rings[j]);
6888da14cebeSEric Cheng }
68890dc2366fSVenugopal Iyer goto bail;
6890da14cebeSEric Cheng }
6891da14cebeSEric Cheng }
6892da14cebeSEric Cheng break;
6893da14cebeSEric Cheng
6894da14cebeSEric Cheng case MAC_RING_TYPE_TX: {
6895da14cebeSEric Cheng mac_ring_t *tmp_ring;
6896da14cebeSEric Cheng
6897da14cebeSEric Cheng /* move the TX rings to the new group */
6898da14cebeSEric Cheng for (i = 0; i < nrings; i++) {
6899da14cebeSEric Cheng /* get the desired ring */
6900da14cebeSEric Cheng tmp_ring = mac_reserve_tx_ring(mip, rings[i]);
69010dc2366fSVenugopal Iyer if (tmp_ring == NULL) {
69020dc2366fSVenugopal Iyer rv = ENOSPC;
69030dc2366fSVenugopal Iyer goto bail;
69040dc2366fSVenugopal Iyer }
6905da14cebeSEric Cheng ASSERT(tmp_ring == rings[i]);
6906da14cebeSEric Cheng rv = mac_group_mov_ring(mip, new_group, rings[i]);
6907da14cebeSEric Cheng if (rv != 0) {
6908da14cebeSEric Cheng /* cleanup on failure */
6909da14cebeSEric Cheng for (j = 0; j < i; j++) {
6910da14cebeSEric Cheng (void) mac_group_mov_ring(mip,
69110dc2366fSVenugopal Iyer MAC_DEFAULT_TX_GROUP(mip),
69120dc2366fSVenugopal Iyer rings[j]);
6913da14cebeSEric Cheng }
69140dc2366fSVenugopal Iyer goto bail;
6915da14cebeSEric Cheng }
6916da14cebeSEric Cheng }
6917da14cebeSEric Cheng break;
6918da14cebeSEric Cheng }
6919da14cebeSEric Cheng }
6920da14cebeSEric Cheng
6921da14cebeSEric Cheng /* add group to share */
692236f99a58SToomas Soome if (share != 0)
6923da14cebeSEric Cheng mip->mi_share_capab.ms_sadd(share, new_group->mrg_driver);
69240dc2366fSVenugopal Iyer
69250dc2366fSVenugopal Iyer bail:
6926da14cebeSEric Cheng /* free temporary array of rings */
6927da14cebeSEric Cheng kmem_free(rings, nrings * sizeof (mac_ring_handle_t));
6928da14cebeSEric Cheng
69290dc2366fSVenugopal Iyer return (rv);
6930da14cebeSEric Cheng }
6931da14cebeSEric Cheng
6932da14cebeSEric Cheng void
mac_group_add_client(mac_group_t * grp,mac_client_impl_t * mcip)69330dc2366fSVenugopal Iyer mac_group_add_client(mac_group_t *grp, mac_client_impl_t *mcip)
6934da14cebeSEric Cheng {
6935da14cebeSEric Cheng mac_grp_client_t *mgcp;
6936da14cebeSEric Cheng
6937da14cebeSEric Cheng for (mgcp = grp->mrg_clients; mgcp != NULL; mgcp = mgcp->mgc_next) {
6938da14cebeSEric Cheng if (mgcp->mgc_client == mcip)
6939da14cebeSEric Cheng break;
6940da14cebeSEric Cheng }
6941da14cebeSEric Cheng
694284de666eSRyan Zezeski ASSERT(mgcp == NULL);
6943da14cebeSEric Cheng
6944da14cebeSEric Cheng mgcp = kmem_zalloc(sizeof (mac_grp_client_t), KM_SLEEP);
6945da14cebeSEric Cheng mgcp->mgc_client = mcip;
6946da14cebeSEric Cheng mgcp->mgc_next = grp->mrg_clients;
6947da14cebeSEric Cheng grp->mrg_clients = mgcp;
6948da14cebeSEric Cheng }
6949da14cebeSEric Cheng
6950da14cebeSEric Cheng void
mac_group_remove_client(mac_group_t * grp,mac_client_impl_t * mcip)69510dc2366fSVenugopal Iyer mac_group_remove_client(mac_group_t *grp, mac_client_impl_t *mcip)
6952da14cebeSEric Cheng {
6953da14cebeSEric Cheng mac_grp_client_t *mgcp, **pprev;
6954da14cebeSEric Cheng
6955da14cebeSEric Cheng for (pprev = &grp->mrg_clients, mgcp = *pprev; mgcp != NULL;
6956da14cebeSEric Cheng pprev = &mgcp->mgc_next, mgcp = *pprev) {
6957da14cebeSEric Cheng if (mgcp->mgc_client == mcip)
6958da14cebeSEric Cheng break;
6959da14cebeSEric Cheng }
6960da14cebeSEric Cheng
6961da14cebeSEric Cheng ASSERT(mgcp != NULL);
6962da14cebeSEric Cheng
6963da14cebeSEric Cheng *pprev = mgcp->mgc_next;
6964da14cebeSEric Cheng kmem_free(mgcp, sizeof (mac_grp_client_t));
6965da14cebeSEric Cheng }
6966da14cebeSEric Cheng
6967da14cebeSEric Cheng /*
696884de666eSRyan Zezeski * Return true if any client on this group explicitly asked for HW
696984de666eSRyan Zezeski * rings (of type mask) or have a bound share.
697084de666eSRyan Zezeski */
697184de666eSRyan Zezeski static boolean_t
i_mac_clients_hw(mac_group_t * grp,uint32_t mask)697284de666eSRyan Zezeski i_mac_clients_hw(mac_group_t *grp, uint32_t mask)
697384de666eSRyan Zezeski {
697484de666eSRyan Zezeski mac_grp_client_t *mgcip;
697584de666eSRyan Zezeski mac_client_impl_t *mcip;
697684de666eSRyan Zezeski mac_resource_props_t *mrp;
697784de666eSRyan Zezeski
697884de666eSRyan Zezeski for (mgcip = grp->mrg_clients; mgcip != NULL; mgcip = mgcip->mgc_next) {
697984de666eSRyan Zezeski mcip = mgcip->mgc_client;
698084de666eSRyan Zezeski mrp = MCIP_RESOURCE_PROPS(mcip);
698184de666eSRyan Zezeski if (mcip->mci_share != 0 || (mrp->mrp_mask & mask) != 0)
698284de666eSRyan Zezeski return (B_TRUE);
698384de666eSRyan Zezeski }
698484de666eSRyan Zezeski
698584de666eSRyan Zezeski return (B_FALSE);
698684de666eSRyan Zezeski }
698784de666eSRyan Zezeski
698884de666eSRyan Zezeski /*
6989da14cebeSEric Cheng * Finds an available group and exclusively reserves it for a client.
6990da14cebeSEric Cheng * The group is chosen to suit the flow's resource controls (bandwidth and
6991da14cebeSEric Cheng * fanout requirements) and the address type.
6992da14cebeSEric Cheng * If the requestor is the pimary MAC then return the group with the
6993da14cebeSEric Cheng * largest number of rings, otherwise the default ring when available.
6994da14cebeSEric Cheng */
6995da14cebeSEric Cheng mac_group_t *
mac_reserve_rx_group(mac_client_impl_t * mcip,uint8_t * mac_addr,boolean_t move)69960dc2366fSVenugopal Iyer mac_reserve_rx_group(mac_client_impl_t *mcip, uint8_t *mac_addr, boolean_t move)
6997da14cebeSEric Cheng {
6998da14cebeSEric Cheng mac_share_handle_t share = mcip->mci_share;
6999da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
7000da14cebeSEric Cheng mac_group_t *grp = NULL;
70010dc2366fSVenugopal Iyer int i;
70020dc2366fSVenugopal Iyer int err = 0;
7003da14cebeSEric Cheng mac_address_t *map;
70040dc2366fSVenugopal Iyer mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
70050dc2366fSVenugopal Iyer int nrings;
70060dc2366fSVenugopal Iyer int donor_grp_rcnt;
70070dc2366fSVenugopal Iyer boolean_t need_exclgrp = B_FALSE;
70080dc2366fSVenugopal Iyer int need_rings = 0;
70090dc2366fSVenugopal Iyer mac_group_t *candidate_grp = NULL;
70100dc2366fSVenugopal Iyer mac_client_impl_t *gclient;
70110dc2366fSVenugopal Iyer mac_group_t *donorgrp = NULL;
70120dc2366fSVenugopal Iyer boolean_t rxhw = mrp->mrp_mask & MRP_RX_RINGS;
70130dc2366fSVenugopal Iyer boolean_t unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC;
70140dc2366fSVenugopal Iyer boolean_t isprimary;
7015da14cebeSEric Cheng
7016da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
7017da14cebeSEric Cheng
70180dc2366fSVenugopal Iyer isprimary = mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC;
7019da14cebeSEric Cheng
70200dc2366fSVenugopal Iyer /*
702184de666eSRyan Zezeski * Check if a group already has this MAC address (case of VLANs)
70220dc2366fSVenugopal Iyer * unless we are moving this MAC client from one group to another.
70230dc2366fSVenugopal Iyer */
70240dc2366fSVenugopal Iyer if (!move && (map = mac_find_macaddr(mip, mac_addr)) != NULL) {
70250dc2366fSVenugopal Iyer if (map->ma_group != NULL)
70260dc2366fSVenugopal Iyer return (map->ma_group);
70270dc2366fSVenugopal Iyer }
702884de666eSRyan Zezeski
70290dc2366fSVenugopal Iyer if (mip->mi_rx_groups == NULL || mip->mi_rx_group_count == 0)
7030da14cebeSEric Cheng return (NULL);
703184de666eSRyan Zezeski
70320dc2366fSVenugopal Iyer /*
703384de666eSRyan Zezeski * If this client is requesting exclusive MAC access then
703484de666eSRyan Zezeski * return NULL to ensure the client uses the default group.
70350dc2366fSVenugopal Iyer */
70360dc2366fSVenugopal Iyer if (mcip->mci_state_flags & MCIS_EXCLUSIVE)
70370dc2366fSVenugopal Iyer return (NULL);
70380dc2366fSVenugopal Iyer
70390dc2366fSVenugopal Iyer /* For dynamic groups default unspecified to 1 */
70400dc2366fSVenugopal Iyer if (rxhw && unspec &&
70410dc2366fSVenugopal Iyer mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
70420dc2366fSVenugopal Iyer mrp->mrp_nrxrings = 1;
70430dc2366fSVenugopal Iyer }
704484de666eSRyan Zezeski
70450dc2366fSVenugopal Iyer /*
70460dc2366fSVenugopal Iyer * For static grouping we allow only specifying rings=0 and
70470dc2366fSVenugopal Iyer * unspecified
70480dc2366fSVenugopal Iyer */
70490dc2366fSVenugopal Iyer if (rxhw && mrp->mrp_nrxrings > 0 &&
70500dc2366fSVenugopal Iyer mip->mi_rx_group_type == MAC_GROUP_TYPE_STATIC) {
70510dc2366fSVenugopal Iyer return (NULL);
70520dc2366fSVenugopal Iyer }
705384de666eSRyan Zezeski
70540dc2366fSVenugopal Iyer if (rxhw) {
70550dc2366fSVenugopal Iyer /*
70560dc2366fSVenugopal Iyer * We have explicitly asked for a group (with nrxrings,
70570dc2366fSVenugopal Iyer * if unspec).
70580dc2366fSVenugopal Iyer */
70590dc2366fSVenugopal Iyer if (unspec || mrp->mrp_nrxrings > 0) {
70600dc2366fSVenugopal Iyer need_exclgrp = B_TRUE;
70610dc2366fSVenugopal Iyer need_rings = mrp->mrp_nrxrings;
70620dc2366fSVenugopal Iyer } else if (mrp->mrp_nrxrings == 0) {
70630dc2366fSVenugopal Iyer /*
70640dc2366fSVenugopal Iyer * We have asked for a software group.
70650dc2366fSVenugopal Iyer */
70660dc2366fSVenugopal Iyer return (NULL);
70670dc2366fSVenugopal Iyer }
70680dc2366fSVenugopal Iyer } else if (isprimary && mip->mi_nactiveclients == 1 &&
70690dc2366fSVenugopal Iyer mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
70700dc2366fSVenugopal Iyer /*
70710dc2366fSVenugopal Iyer * If the primary is the only active client on this
70720dc2366fSVenugopal Iyer * mip and we have not asked for any rings, we give
70730dc2366fSVenugopal Iyer * it the default group so that the primary gets to
70740dc2366fSVenugopal Iyer * use all the rings.
70750dc2366fSVenugopal Iyer */
70760dc2366fSVenugopal Iyer return (NULL);
70770dc2366fSVenugopal Iyer }
70780dc2366fSVenugopal Iyer
70790dc2366fSVenugopal Iyer /* The group that can donate rings */
70800dc2366fSVenugopal Iyer donorgrp = mip->mi_rx_donor_grp;
70810dc2366fSVenugopal Iyer
70820dc2366fSVenugopal Iyer /*
70830dc2366fSVenugopal Iyer * The number of rings that the default group can donate.
70840dc2366fSVenugopal Iyer * We need to leave at least one ring.
70850dc2366fSVenugopal Iyer */
70860dc2366fSVenugopal Iyer donor_grp_rcnt = donorgrp->mrg_cur_count - 1;
7087da14cebeSEric Cheng
7088da14cebeSEric Cheng /*
7089da14cebeSEric Cheng * Try to exclusively reserve a RX group.
7090da14cebeSEric Cheng *
70910dc2366fSVenugopal Iyer * For flows requiring HW_DEFAULT_RING (unicast flow of the primary
70920dc2366fSVenugopal Iyer * client), try to reserve the a non-default RX group and give
70930dc2366fSVenugopal Iyer * it all the rings from the donor group, except the default ring
7094da14cebeSEric Cheng *
70950dc2366fSVenugopal Iyer * For flows requiring HW_RING (unicast flow of other clients), try
70960dc2366fSVenugopal Iyer * to reserve non-default RX group with the specified number of
70970dc2366fSVenugopal Iyer * rings, if available.
7098da14cebeSEric Cheng *
70990dc2366fSVenugopal Iyer * For flows that have not asked for software or hardware ring,
71000dc2366fSVenugopal Iyer * try to reserve a non-default group with 1 ring, if available.
7101da14cebeSEric Cheng */
71020dc2366fSVenugopal Iyer for (i = 1; i < mip->mi_rx_group_count; i++) {
71030dc2366fSVenugopal Iyer grp = &mip->mi_rx_groups[i];
7104da14cebeSEric Cheng
7105da14cebeSEric Cheng DTRACE_PROBE3(rx__group__trying, char *, mip->mi_name,
7106da14cebeSEric Cheng int, grp->mrg_index, mac_group_state_t, grp->mrg_state);
7107da14cebeSEric Cheng
7108da14cebeSEric Cheng /*
71090dc2366fSVenugopal Iyer * Check if this group could be a candidate group for
71100dc2366fSVenugopal Iyer * eviction if we need a group for this MAC client,
71110dc2366fSVenugopal Iyer * but there aren't any. A candidate group is one
71120dc2366fSVenugopal Iyer * that didn't ask for an exclusive group, but got
71130dc2366fSVenugopal Iyer * one and it has enough rings (combined with what
71140dc2366fSVenugopal Iyer * the donor group can donate) for the new MAC
711584de666eSRyan Zezeski * client.
7116da14cebeSEric Cheng */
71170dc2366fSVenugopal Iyer if (grp->mrg_state >= MAC_GROUP_STATE_RESERVED) {
71180dc2366fSVenugopal Iyer /*
711984de666eSRyan Zezeski * If the donor group is not the default
712084de666eSRyan Zezeski * group, don't bother looking for a candidate
712184de666eSRyan Zezeski * group. If we don't have enough rings we
712284de666eSRyan Zezeski * will check if the primary group can be
712384de666eSRyan Zezeski * vacated.
71240dc2366fSVenugopal Iyer */
71250dc2366fSVenugopal Iyer if (candidate_grp == NULL &&
71260dc2366fSVenugopal Iyer donorgrp == MAC_DEFAULT_RX_GROUP(mip)) {
712784de666eSRyan Zezeski if (!i_mac_clients_hw(grp, MRP_RX_RINGS) &&
71280dc2366fSVenugopal Iyer (unspec ||
71290dc2366fSVenugopal Iyer (grp->mrg_cur_count + donor_grp_rcnt >=
71300dc2366fSVenugopal Iyer need_rings))) {
71310dc2366fSVenugopal Iyer candidate_grp = grp;
71320dc2366fSVenugopal Iyer }
71330dc2366fSVenugopal Iyer }
7134da14cebeSEric Cheng continue;
7135da14cebeSEric Cheng }
7136da14cebeSEric Cheng /*
7137da14cebeSEric Cheng * This group could already be SHARED by other multicast
7138da14cebeSEric Cheng * flows on this client. In that case, the group would
7139da14cebeSEric Cheng * be shared and has already been started.
7140da14cebeSEric Cheng */
7141da14cebeSEric Cheng ASSERT(grp->mrg_state != MAC_GROUP_STATE_UNINIT);
7142da14cebeSEric Cheng
7143da14cebeSEric Cheng if ((grp->mrg_state == MAC_GROUP_STATE_REGISTERED) &&
7144da14cebeSEric Cheng (mac_start_group(grp) != 0)) {
7145da14cebeSEric Cheng continue;
7146da14cebeSEric Cheng }
7147da14cebeSEric Cheng
71480dc2366fSVenugopal Iyer if (mip->mi_rx_group_type != MAC_GROUP_TYPE_DYNAMIC)
7149da14cebeSEric Cheng break;
7150da14cebeSEric Cheng ASSERT(grp->mrg_cur_count == 0);
7151da14cebeSEric Cheng
7152da14cebeSEric Cheng /*
7153da14cebeSEric Cheng * Populate the group. Rings should be taken
71540dc2366fSVenugopal Iyer * from the donor group.
7155da14cebeSEric Cheng */
71560dc2366fSVenugopal Iyer nrings = rxhw ? need_rings : isprimary ? donor_grp_rcnt: 1;
7157da14cebeSEric Cheng
71580dc2366fSVenugopal Iyer /*
71590dc2366fSVenugopal Iyer * If the donor group can't donate, let's just walk and
71600dc2366fSVenugopal Iyer * see if someone can vacate a group, so that we have
71610dc2366fSVenugopal Iyer * enough rings for this, unless we already have
71620dc2366fSVenugopal Iyer * identified a candiate group..
71630dc2366fSVenugopal Iyer */
71640dc2366fSVenugopal Iyer if (nrings <= donor_grp_rcnt) {
7165da14cebeSEric Cheng err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_RX,
71660dc2366fSVenugopal Iyer donorgrp, grp, share, nrings);
71670dc2366fSVenugopal Iyer if (err == 0) {
71680dc2366fSVenugopal Iyer /*
71690dc2366fSVenugopal Iyer * For a share i_mac_group_allocate_rings gets
71700dc2366fSVenugopal Iyer * the rings from the driver, let's populate
71710dc2366fSVenugopal Iyer * the property for the client now.
71720dc2366fSVenugopal Iyer */
717336f99a58SToomas Soome if (share != 0) {
71740dc2366fSVenugopal Iyer mac_client_set_rings(
71750dc2366fSVenugopal Iyer (mac_client_handle_t)mcip,
71760dc2366fSVenugopal Iyer grp->mrg_cur_count, -1);
71770dc2366fSVenugopal Iyer }
71780dc2366fSVenugopal Iyer if (mac_is_primary_client(mcip) && !rxhw)
71790dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = grp;
7180da14cebeSEric Cheng break;
71810dc2366fSVenugopal Iyer }
71820dc2366fSVenugopal Iyer }
7183da14cebeSEric Cheng
7184da14cebeSEric Cheng DTRACE_PROBE3(rx__group__reserve__alloc__rings, char *,
7185da14cebeSEric Cheng mip->mi_name, int, grp->mrg_index, int, err);
7186da14cebeSEric Cheng
7187da14cebeSEric Cheng /*
71880dc2366fSVenugopal Iyer * It's a dynamic group but the grouping operation
71890dc2366fSVenugopal Iyer * failed.
7190da14cebeSEric Cheng */
7191da14cebeSEric Cheng mac_stop_group(grp);
7192da14cebeSEric Cheng }
719384de666eSRyan Zezeski
71940dc2366fSVenugopal Iyer /* We didn't find an exclusive group for this MAC client */
71950dc2366fSVenugopal Iyer if (i >= mip->mi_rx_group_count) {
7196da14cebeSEric Cheng
71970dc2366fSVenugopal Iyer if (!need_exclgrp)
7198da14cebeSEric Cheng return (NULL);
7199da14cebeSEric Cheng
72000dc2366fSVenugopal Iyer /*
720184de666eSRyan Zezeski * If we found a candidate group then move the
720284de666eSRyan Zezeski * existing MAC client from the candidate_group to the
720384de666eSRyan Zezeski * default group and give the candidate_group to the
720484de666eSRyan Zezeski * new MAC client. If we didn't find a candidate
720584de666eSRyan Zezeski * group, then check if the primary is in its own
720684de666eSRyan Zezeski * group and if it can make way for this MAC client.
72070dc2366fSVenugopal Iyer */
72080dc2366fSVenugopal Iyer if (candidate_grp == NULL &&
72090dc2366fSVenugopal Iyer donorgrp != MAC_DEFAULT_RX_GROUP(mip) &&
72100dc2366fSVenugopal Iyer donorgrp->mrg_cur_count >= need_rings) {
72110dc2366fSVenugopal Iyer candidate_grp = donorgrp;
72120dc2366fSVenugopal Iyer }
72130dc2366fSVenugopal Iyer if (candidate_grp != NULL) {
72140dc2366fSVenugopal Iyer boolean_t prim_grp = B_FALSE;
72150dc2366fSVenugopal Iyer
72160dc2366fSVenugopal Iyer /*
721784de666eSRyan Zezeski * Switch the existing MAC client from the
721884de666eSRyan Zezeski * candidate group to the default group. If
721984de666eSRyan Zezeski * the candidate group is the donor group,
722084de666eSRyan Zezeski * then after the switch we need to update the
722184de666eSRyan Zezeski * donor group too.
72220dc2366fSVenugopal Iyer */
72230dc2366fSVenugopal Iyer grp = candidate_grp;
722484de666eSRyan Zezeski gclient = grp->mrg_clients->mgc_client;
722584de666eSRyan Zezeski VERIFY3P(gclient, !=, NULL);
72260dc2366fSVenugopal Iyer if (grp == mip->mi_rx_donor_grp)
72270dc2366fSVenugopal Iyer prim_grp = B_TRUE;
72280dc2366fSVenugopal Iyer if (mac_rx_switch_group(gclient, grp,
72290dc2366fSVenugopal Iyer MAC_DEFAULT_RX_GROUP(mip)) != 0) {
72300dc2366fSVenugopal Iyer return (NULL);
72310dc2366fSVenugopal Iyer }
72320dc2366fSVenugopal Iyer if (prim_grp) {
72330dc2366fSVenugopal Iyer mip->mi_rx_donor_grp =
72340dc2366fSVenugopal Iyer MAC_DEFAULT_RX_GROUP(mip);
72350dc2366fSVenugopal Iyer donorgrp = MAC_DEFAULT_RX_GROUP(mip);
72360dc2366fSVenugopal Iyer }
72370dc2366fSVenugopal Iyer
72380dc2366fSVenugopal Iyer /*
72390dc2366fSVenugopal Iyer * Now give this group with the required rings
72400dc2366fSVenugopal Iyer * to this MAC client.
72410dc2366fSVenugopal Iyer */
72420dc2366fSVenugopal Iyer ASSERT(grp->mrg_state == MAC_GROUP_STATE_REGISTERED);
72430dc2366fSVenugopal Iyer if (mac_start_group(grp) != 0)
72440dc2366fSVenugopal Iyer return (NULL);
72450dc2366fSVenugopal Iyer
72460dc2366fSVenugopal Iyer if (mip->mi_rx_group_type != MAC_GROUP_TYPE_DYNAMIC)
72470dc2366fSVenugopal Iyer return (grp);
72480dc2366fSVenugopal Iyer
72490dc2366fSVenugopal Iyer donor_grp_rcnt = donorgrp->mrg_cur_count - 1;
72500dc2366fSVenugopal Iyer ASSERT(grp->mrg_cur_count == 0);
72510dc2366fSVenugopal Iyer ASSERT(donor_grp_rcnt >= need_rings);
72520dc2366fSVenugopal Iyer err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_RX,
72530dc2366fSVenugopal Iyer donorgrp, grp, share, need_rings);
72540dc2366fSVenugopal Iyer if (err == 0) {
72550dc2366fSVenugopal Iyer /*
72560dc2366fSVenugopal Iyer * For a share i_mac_group_allocate_rings gets
72570dc2366fSVenugopal Iyer * the rings from the driver, let's populate
72580dc2366fSVenugopal Iyer * the property for the client now.
72590dc2366fSVenugopal Iyer */
726036f99a58SToomas Soome if (share != 0) {
72610dc2366fSVenugopal Iyer mac_client_set_rings(
72620dc2366fSVenugopal Iyer (mac_client_handle_t)mcip,
72630dc2366fSVenugopal Iyer grp->mrg_cur_count, -1);
72640dc2366fSVenugopal Iyer }
72650dc2366fSVenugopal Iyer DTRACE_PROBE2(rx__group__reserved,
72660dc2366fSVenugopal Iyer char *, mip->mi_name, int, grp->mrg_index);
72670dc2366fSVenugopal Iyer return (grp);
72680dc2366fSVenugopal Iyer }
72690dc2366fSVenugopal Iyer DTRACE_PROBE3(rx__group__reserve__alloc__rings, char *,
72700dc2366fSVenugopal Iyer mip->mi_name, int, grp->mrg_index, int, err);
72710dc2366fSVenugopal Iyer mac_stop_group(grp);
72720dc2366fSVenugopal Iyer }
72730dc2366fSVenugopal Iyer return (NULL);
72740dc2366fSVenugopal Iyer }
7275da14cebeSEric Cheng ASSERT(grp != NULL);
7276da14cebeSEric Cheng
7277da14cebeSEric Cheng DTRACE_PROBE2(rx__group__reserved,
7278da14cebeSEric Cheng char *, mip->mi_name, int, grp->mrg_index);
7279da14cebeSEric Cheng return (grp);
7280da14cebeSEric Cheng }
7281da14cebeSEric Cheng
7282da14cebeSEric Cheng /*
7283da14cebeSEric Cheng * mac_rx_release_group()
7284da14cebeSEric Cheng *
728584de666eSRyan Zezeski * Release the group when it has no remaining clients. The group is
728684de666eSRyan Zezeski * stopped and its shares are removed and all rings are assigned back
728784de666eSRyan Zezeski * to default group. This should never be called against the default
728884de666eSRyan Zezeski * group.
7289da14cebeSEric Cheng */
7290da14cebeSEric Cheng void
mac_release_rx_group(mac_client_impl_t * mcip,mac_group_t * group)7291da14cebeSEric Cheng mac_release_rx_group(mac_client_impl_t *mcip, mac_group_t *group)
7292da14cebeSEric Cheng {
7293da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip;
7294da14cebeSEric Cheng mac_ring_t *ring;
7295da14cebeSEric Cheng
72960dc2366fSVenugopal Iyer ASSERT(group != MAC_DEFAULT_RX_GROUP(mip));
729784de666eSRyan Zezeski ASSERT(MAC_GROUP_NO_CLIENT(group) == B_TRUE);
72980dc2366fSVenugopal Iyer
72990dc2366fSVenugopal Iyer if (mip->mi_rx_donor_grp == group)
73000dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = MAC_DEFAULT_RX_GROUP(mip);
7301da14cebeSEric Cheng
7302da14cebeSEric Cheng /*
7303da14cebeSEric Cheng * This is the case where there are no clients left. Any
7304da14cebeSEric Cheng * SRS etc on this group have also be quiesced.
7305da14cebeSEric Cheng */
7306da14cebeSEric Cheng for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
7307da14cebeSEric Cheng if (ring->mr_classify_type == MAC_HW_CLASSIFIER) {
7308da14cebeSEric Cheng ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED);
7309da14cebeSEric Cheng /*
7310da14cebeSEric Cheng * Remove the SRS associated with the HW ring.
7311da14cebeSEric Cheng * As a result, polling will be disabled.
7312da14cebeSEric Cheng */
7313da14cebeSEric Cheng ring->mr_srs = NULL;
7314da14cebeSEric Cheng }
73150dc2366fSVenugopal Iyer ASSERT(group->mrg_state < MAC_GROUP_STATE_RESERVED ||
73160dc2366fSVenugopal Iyer ring->mr_state == MR_INUSE);
73170dc2366fSVenugopal Iyer if (ring->mr_state == MR_INUSE) {
7318da14cebeSEric Cheng mac_stop_ring(ring);
7319da14cebeSEric Cheng ring->mr_flag = 0;
7320da14cebeSEric Cheng }
73210dc2366fSVenugopal Iyer }
7322da14cebeSEric Cheng
7323da14cebeSEric Cheng /* remove group from share */
732436f99a58SToomas Soome if (mcip->mci_share != 0) {
7325da14cebeSEric Cheng mip->mi_share_capab.ms_sremove(mcip->mci_share,
7326da14cebeSEric Cheng group->mrg_driver);
7327da14cebeSEric Cheng }
7328da14cebeSEric Cheng
7329da14cebeSEric Cheng if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
7330da14cebeSEric Cheng mac_ring_t *ring;
7331da14cebeSEric Cheng
7332da14cebeSEric Cheng /*
7333da14cebeSEric Cheng * Rings were dynamically allocated to group.
7334da14cebeSEric Cheng * Move rings back to default group.
7335da14cebeSEric Cheng */
7336da14cebeSEric Cheng while ((ring = group->mrg_rings) != NULL) {
73370dc2366fSVenugopal Iyer (void) mac_group_mov_ring(mip, mip->mi_rx_donor_grp,
73380dc2366fSVenugopal Iyer ring);
7339da14cebeSEric Cheng }
7340da14cebeSEric Cheng }
7341da14cebeSEric Cheng mac_stop_group(group);
7342da14cebeSEric Cheng /*
7343da14cebeSEric Cheng * Possible improvement: See if we can assign the group just released
7344da14cebeSEric Cheng * to a another client of the mip
7345da14cebeSEric Cheng */
7346da14cebeSEric Cheng }
7347da14cebeSEric Cheng
7348da14cebeSEric Cheng /*
734984de666eSRyan Zezeski * Move the MAC address from fgrp to tgrp.
73500dc2366fSVenugopal Iyer */
73510dc2366fSVenugopal Iyer static int
mac_rx_move_macaddr(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)73520dc2366fSVenugopal Iyer mac_rx_move_macaddr(mac_client_impl_t *mcip, mac_group_t *fgrp,
73530dc2366fSVenugopal Iyer mac_group_t *tgrp)
73540dc2366fSVenugopal Iyer {
73550dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
73560dc2366fSVenugopal Iyer uint8_t maddr[MAXMACADDRLEN];
73570dc2366fSVenugopal Iyer int err = 0;
735884de666eSRyan Zezeski uint16_t vid;
735984de666eSRyan Zezeski mac_unicast_impl_t *muip;
736084de666eSRyan Zezeski boolean_t use_hw;
73610dc2366fSVenugopal Iyer
73620dc2366fSVenugopal Iyer mac_rx_client_quiesce((mac_client_handle_t)mcip);
736384de666eSRyan Zezeski VERIFY3P(mcip->mci_unicast, !=, NULL);
73640dc2366fSVenugopal Iyer bcopy(mcip->mci_unicast->ma_addr, maddr, mcip->mci_unicast->ma_len);
73650dc2366fSVenugopal Iyer
736684de666eSRyan Zezeski /*
736784de666eSRyan Zezeski * Does the client require MAC address hardware classifiction?
736884de666eSRyan Zezeski */
736984de666eSRyan Zezeski use_hw = (mcip->mci_state_flags & MCIS_UNICAST_HW) != 0;
737084de666eSRyan Zezeski vid = i_mac_flow_vid(mcip->mci_flent);
737184de666eSRyan Zezeski
737284de666eSRyan Zezeski /*
737384de666eSRyan Zezeski * You can never move an address that is shared by multiple
737484de666eSRyan Zezeski * clients. mac_datapath_setup() ensures that clients sharing
737584de666eSRyan Zezeski * an address are placed on the default group. This guarantees
737684de666eSRyan Zezeski * that a non-default group will only ever have one client and
737784de666eSRyan Zezeski * thus make full use of HW filters.
737884de666eSRyan Zezeski */
737984de666eSRyan Zezeski if (mac_check_macaddr_shared(mcip->mci_unicast))
738084de666eSRyan Zezeski return (EINVAL);
738184de666eSRyan Zezeski
738284de666eSRyan Zezeski err = mac_remove_macaddr_vlan(mcip->mci_unicast, vid);
738384de666eSRyan Zezeski
73840dc2366fSVenugopal Iyer if (err != 0) {
73850dc2366fSVenugopal Iyer mac_rx_client_restart((mac_client_handle_t)mcip);
73860dc2366fSVenugopal Iyer return (err);
73870dc2366fSVenugopal Iyer }
738884de666eSRyan Zezeski
73890dc2366fSVenugopal Iyer /*
739084de666eSRyan Zezeski * If this isn't the primary MAC address then the
739184de666eSRyan Zezeski * mac_address_t has been freed by the last call to
739284de666eSRyan Zezeski * mac_remove_macaddr_vlan(). In any case, NULL the reference
739384de666eSRyan Zezeski * to avoid a dangling pointer.
73940dc2366fSVenugopal Iyer */
739584de666eSRyan Zezeski mcip->mci_unicast = NULL;
739684de666eSRyan Zezeski
739784de666eSRyan Zezeski /*
739884de666eSRyan Zezeski * We also have to NULL all the mui_map references -- sun4v
739984de666eSRyan Zezeski * strikes again!
740084de666eSRyan Zezeski */
740184de666eSRyan Zezeski rw_enter(&mcip->mci_rw_lock, RW_WRITER);
740284de666eSRyan Zezeski for (muip = mcip->mci_unicast_list; muip != NULL; muip = muip->mui_next)
740384de666eSRyan Zezeski muip->mui_map = NULL;
740484de666eSRyan Zezeski rw_exit(&mcip->mci_rw_lock);
740584de666eSRyan Zezeski
740684de666eSRyan Zezeski /*
740784de666eSRyan Zezeski * Program the H/W Classifier first, if this fails we need not
740884de666eSRyan Zezeski * proceed with the other stuff.
740984de666eSRyan Zezeski */
741084de666eSRyan Zezeski if ((err = mac_add_macaddr_vlan(mip, tgrp, maddr, vid, use_hw)) != 0) {
741184de666eSRyan Zezeski int err2;
741284de666eSRyan Zezeski
74130dc2366fSVenugopal Iyer /* Revert back the H/W Classifier */
741484de666eSRyan Zezeski err2 = mac_add_macaddr_vlan(mip, fgrp, maddr, vid, use_hw);
741584de666eSRyan Zezeski
741684de666eSRyan Zezeski if (err2 != 0) {
741784de666eSRyan Zezeski cmn_err(CE_WARN, "Failed to revert HW classification"
741884de666eSRyan Zezeski " on MAC %s, for client %s: %d.", mip->mi_name,
741984de666eSRyan Zezeski mcip->mci_name, err2);
742084de666eSRyan Zezeski }
742184de666eSRyan Zezeski
742284de666eSRyan Zezeski mac_rx_client_restart((mac_client_handle_t)mcip);
742384de666eSRyan Zezeski return (err);
742484de666eSRyan Zezeski }
742584de666eSRyan Zezeski
74260dc2366fSVenugopal Iyer /*
742784de666eSRyan Zezeski * Get a reference to the new mac_address_t and update the
742884de666eSRyan Zezeski * client's reference. Then restart the client and add the
742984de666eSRyan Zezeski * other clients of this MAC addr (if they exsit).
74300dc2366fSVenugopal Iyer */
74310dc2366fSVenugopal Iyer mcip->mci_unicast = mac_find_macaddr(mip, maddr);
743284de666eSRyan Zezeski rw_enter(&mcip->mci_rw_lock, RW_WRITER);
743384de666eSRyan Zezeski for (muip = mcip->mci_unicast_list; muip != NULL; muip = muip->mui_next)
743484de666eSRyan Zezeski muip->mui_map = mcip->mci_unicast;
743584de666eSRyan Zezeski rw_exit(&mcip->mci_rw_lock);
74360dc2366fSVenugopal Iyer mac_rx_client_restart((mac_client_handle_t)mcip);
743784de666eSRyan Zezeski return (0);
74380dc2366fSVenugopal Iyer }
74390dc2366fSVenugopal Iyer
74400dc2366fSVenugopal Iyer /*
74410dc2366fSVenugopal Iyer * Switch the MAC client from one group to another. This means we need
74420dc2366fSVenugopal Iyer * to remove the MAC address from the group, remove the MAC client,
74430dc2366fSVenugopal Iyer * teardown the SRSs and revert the group state. Then, we add the client
74440dc2366fSVenugopal Iyer * to the destination group, set the SRSs, and add the MAC address to the
74450dc2366fSVenugopal Iyer * group.
74460dc2366fSVenugopal Iyer */
74470dc2366fSVenugopal Iyer int
mac_rx_switch_group(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)74480dc2366fSVenugopal Iyer mac_rx_switch_group(mac_client_impl_t *mcip, mac_group_t *fgrp,
74490dc2366fSVenugopal Iyer mac_group_t *tgrp)
74500dc2366fSVenugopal Iyer {
74510dc2366fSVenugopal Iyer int err;
74520dc2366fSVenugopal Iyer mac_group_state_t next_state;
74530dc2366fSVenugopal Iyer mac_client_impl_t *group_only_mcip;
74540dc2366fSVenugopal Iyer mac_client_impl_t *gmcip;
74550dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
74560dc2366fSVenugopal Iyer mac_grp_client_t *mgcp;
74570dc2366fSVenugopal Iyer
745884de666eSRyan Zezeski VERIFY3P(fgrp, ==, mcip->mci_flent->fe_rx_ring_group);
74590dc2366fSVenugopal Iyer
74600dc2366fSVenugopal Iyer if ((err = mac_rx_move_macaddr(mcip, fgrp, tgrp)) != 0)
74610dc2366fSVenugopal Iyer return (err);
74620dc2366fSVenugopal Iyer
74630dc2366fSVenugopal Iyer /*
746484de666eSRyan Zezeski * If the group is marked as reserved and in use by a single
746584de666eSRyan Zezeski * client, then there is an SRS to teardown.
74660dc2366fSVenugopal Iyer */
74670dc2366fSVenugopal Iyer if (fgrp->mrg_state == MAC_GROUP_STATE_RESERVED &&
74680dc2366fSVenugopal Iyer MAC_GROUP_ONLY_CLIENT(fgrp) != NULL) {
74690dc2366fSVenugopal Iyer mac_rx_srs_group_teardown(mcip->mci_flent, B_TRUE);
74700dc2366fSVenugopal Iyer }
747184de666eSRyan Zezeski
747284de666eSRyan Zezeski /*
747384de666eSRyan Zezeski * If we are moving the client from a non-default group, then
747484de666eSRyan Zezeski * we know that any additional clients on this group share the
747584de666eSRyan Zezeski * same MAC address. Since we moved the MAC address filter, we
747684de666eSRyan Zezeski * need to move these clients too.
747784de666eSRyan Zezeski *
747884de666eSRyan Zezeski * If we are moving the client from the default group and its
747984de666eSRyan Zezeski * MAC address has VLAN clients, then we must move those
748084de666eSRyan Zezeski * clients as well.
748184de666eSRyan Zezeski *
748284de666eSRyan Zezeski * In both cases the idea is the same: we moved the MAC
748384de666eSRyan Zezeski * address filter to the tgrp, so we must move all clients
748484de666eSRyan Zezeski * using that MAC address to tgrp as well.
748584de666eSRyan Zezeski */
74860dc2366fSVenugopal Iyer if (fgrp != MAC_DEFAULT_RX_GROUP(mip)) {
74870dc2366fSVenugopal Iyer mgcp = fgrp->mrg_clients;
74880dc2366fSVenugopal Iyer while (mgcp != NULL) {
74890dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
74900dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
74910dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, gmcip);
74920dc2366fSVenugopal Iyer mac_group_add_client(tgrp, gmcip);
74930dc2366fSVenugopal Iyer gmcip->mci_flent->fe_rx_ring_group = tgrp;
74940dc2366fSVenugopal Iyer }
74950dc2366fSVenugopal Iyer mac_release_rx_group(mcip, fgrp);
749684de666eSRyan Zezeski VERIFY3B(MAC_GROUP_NO_CLIENT(fgrp), ==, B_TRUE);
74970dc2366fSVenugopal Iyer mac_set_group_state(fgrp, MAC_GROUP_STATE_REGISTERED);
74980dc2366fSVenugopal Iyer } else {
74990dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, mcip);
75000dc2366fSVenugopal Iyer mac_group_add_client(tgrp, mcip);
75010dc2366fSVenugopal Iyer mcip->mci_flent->fe_rx_ring_group = tgrp;
750284de666eSRyan Zezeski
75030dc2366fSVenugopal Iyer /*
75040dc2366fSVenugopal Iyer * If there are other clients (VLANs) sharing this address
750584de666eSRyan Zezeski * then move them too.
75060dc2366fSVenugopal Iyer */
750784de666eSRyan Zezeski if (mac_check_macaddr_shared(mcip->mci_unicast)) {
75080dc2366fSVenugopal Iyer /*
75090dc2366fSVenugopal Iyer * We need to move all the clients that are using
751084de666eSRyan Zezeski * this MAC address.
75110dc2366fSVenugopal Iyer */
75120dc2366fSVenugopal Iyer mgcp = fgrp->mrg_clients;
75130dc2366fSVenugopal Iyer while (mgcp != NULL) {
75140dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
75150dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
75160dc2366fSVenugopal Iyer if (mcip->mci_unicast == gmcip->mci_unicast) {
75170dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, gmcip);
75180dc2366fSVenugopal Iyer mac_group_add_client(tgrp, gmcip);
75190dc2366fSVenugopal Iyer gmcip->mci_flent->fe_rx_ring_group =
75200dc2366fSVenugopal Iyer tgrp;
75210dc2366fSVenugopal Iyer }
75220dc2366fSVenugopal Iyer }
75230dc2366fSVenugopal Iyer }
752484de666eSRyan Zezeski
75250dc2366fSVenugopal Iyer /*
752684de666eSRyan Zezeski * The default group still handles multicast and
752784de666eSRyan Zezeski * broadcast traffic; it won't transition to
75280dc2366fSVenugopal Iyer * MAC_GROUP_STATE_REGISTERED.
75290dc2366fSVenugopal Iyer */
75300dc2366fSVenugopal Iyer if (fgrp->mrg_state == MAC_GROUP_STATE_RESERVED)
75310dc2366fSVenugopal Iyer mac_rx_group_unmark(fgrp, MR_CONDEMNED);
75320dc2366fSVenugopal Iyer mac_set_group_state(fgrp, MAC_GROUP_STATE_SHARED);
75330dc2366fSVenugopal Iyer }
753484de666eSRyan Zezeski
75350dc2366fSVenugopal Iyer next_state = mac_group_next_state(tgrp, &group_only_mcip,
75360dc2366fSVenugopal Iyer MAC_DEFAULT_RX_GROUP(mip), B_TRUE);
75370dc2366fSVenugopal Iyer mac_set_group_state(tgrp, next_state);
753884de666eSRyan Zezeski
75390dc2366fSVenugopal Iyer /*
754084de666eSRyan Zezeski * If the destination group is reserved, then setup the SRSes.
754184de666eSRyan Zezeski * Otherwise make sure to use SW classification.
75420dc2366fSVenugopal Iyer */
75430dc2366fSVenugopal Iyer if (tgrp->mrg_state == MAC_GROUP_STATE_RESERVED) {
75440dc2366fSVenugopal Iyer mac_rx_srs_group_setup(mcip, mcip->mci_flent, SRST_LINK);
75450dc2366fSVenugopal Iyer mac_fanout_setup(mcip, mcip->mci_flent,
75460dc2366fSVenugopal Iyer MCIP_RESOURCE_PROPS(mcip), mac_rx_deliver, mcip, NULL,
75470dc2366fSVenugopal Iyer NULL);
75480dc2366fSVenugopal Iyer mac_rx_group_unmark(tgrp, MR_INCIPIENT);
75490dc2366fSVenugopal Iyer } else {
75500dc2366fSVenugopal Iyer mac_rx_switch_grp_to_sw(tgrp);
75510dc2366fSVenugopal Iyer }
755284de666eSRyan Zezeski
75530dc2366fSVenugopal Iyer return (0);
75540dc2366fSVenugopal Iyer }
75550dc2366fSVenugopal Iyer
75560dc2366fSVenugopal Iyer /*
7557da14cebeSEric Cheng * Reserves a TX group for the specified share. Invoked by mac_tx_srs_setup()
7558da14cebeSEric Cheng * when a share was allocated to the client.
7559da14cebeSEric Cheng */
7560da14cebeSEric Cheng mac_group_t *
mac_reserve_tx_group(mac_client_impl_t * mcip,boolean_t move)75610dc2366fSVenugopal Iyer mac_reserve_tx_group(mac_client_impl_t *mcip, boolean_t move)
7562da14cebeSEric Cheng {
75630dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
75640dc2366fSVenugopal Iyer mac_group_t *grp = NULL;
75650dc2366fSVenugopal Iyer int rv;
75660dc2366fSVenugopal Iyer int i;
75670dc2366fSVenugopal Iyer int err;
75680dc2366fSVenugopal Iyer mac_group_t *defgrp;
75690dc2366fSVenugopal Iyer mac_share_handle_t share = mcip->mci_share;
75700dc2366fSVenugopal Iyer mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
75710dc2366fSVenugopal Iyer int nrings;
75720dc2366fSVenugopal Iyer int defnrings;
75730dc2366fSVenugopal Iyer boolean_t need_exclgrp = B_FALSE;
75740dc2366fSVenugopal Iyer int need_rings = 0;
75750dc2366fSVenugopal Iyer mac_group_t *candidate_grp = NULL;
75760dc2366fSVenugopal Iyer mac_client_impl_t *gclient;
75770dc2366fSVenugopal Iyer mac_resource_props_t *gmrp;
75780dc2366fSVenugopal Iyer boolean_t txhw = mrp->mrp_mask & MRP_TX_RINGS;
75790dc2366fSVenugopal Iyer boolean_t unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC;
75800dc2366fSVenugopal Iyer boolean_t isprimary;
7581da14cebeSEric Cheng
75820dc2366fSVenugopal Iyer isprimary = mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC;
758384de666eSRyan Zezeski
7584da14cebeSEric Cheng /*
75850dc2366fSVenugopal Iyer * When we come here for a VLAN on the primary (dladm create-vlan),
75860dc2366fSVenugopal Iyer * we need to pair it along with the primary (to keep it consistent
75870dc2366fSVenugopal Iyer * with the RX side). So, we check if the primary is already assigned
75880dc2366fSVenugopal Iyer * to a group and return the group if so. The other way is also
75890dc2366fSVenugopal Iyer * true, i.e. the VLAN is already created and now we are plumbing
75900dc2366fSVenugopal Iyer * the primary.
7591da14cebeSEric Cheng */
75920dc2366fSVenugopal Iyer if (!move && isprimary) {
75930dc2366fSVenugopal Iyer for (gclient = mip->mi_clients_list; gclient != NULL;
75940dc2366fSVenugopal Iyer gclient = gclient->mci_client_next) {
75950dc2366fSVenugopal Iyer if (gclient->mci_flent->fe_type & FLOW_PRIMARY_MAC &&
75960dc2366fSVenugopal Iyer gclient->mci_flent->fe_tx_ring_group != NULL) {
75970dc2366fSVenugopal Iyer return (gclient->mci_flent->fe_tx_ring_group);
75980dc2366fSVenugopal Iyer }
75990dc2366fSVenugopal Iyer }
7600da14cebeSEric Cheng }
7601da14cebeSEric Cheng
76020dc2366fSVenugopal Iyer if (mip->mi_tx_groups == NULL || mip->mi_tx_group_count == 0)
76030dc2366fSVenugopal Iyer return (NULL);
7604da14cebeSEric Cheng
76050dc2366fSVenugopal Iyer /* For dynamic groups, default unspec to 1 */
76060dc2366fSVenugopal Iyer if (txhw && unspec &&
76070dc2366fSVenugopal Iyer mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
76080dc2366fSVenugopal Iyer mrp->mrp_ntxrings = 1;
76090dc2366fSVenugopal Iyer }
7610da14cebeSEric Cheng /*
76110dc2366fSVenugopal Iyer * For static grouping we allow only specifying rings=0 and
76120dc2366fSVenugopal Iyer * unspecified
7613da14cebeSEric Cheng */
76140dc2366fSVenugopal Iyer if (txhw && mrp->mrp_ntxrings > 0 &&
76150dc2366fSVenugopal Iyer mip->mi_tx_group_type == MAC_GROUP_TYPE_STATIC) {
7616da14cebeSEric Cheng return (NULL);
7617da14cebeSEric Cheng }
7618da14cebeSEric Cheng
76190dc2366fSVenugopal Iyer if (txhw) {
76200dc2366fSVenugopal Iyer /*
76210dc2366fSVenugopal Iyer * We have explicitly asked for a group (with ntxrings,
76220dc2366fSVenugopal Iyer * if unspec).
76230dc2366fSVenugopal Iyer */
76240dc2366fSVenugopal Iyer if (unspec || mrp->mrp_ntxrings > 0) {
76250dc2366fSVenugopal Iyer need_exclgrp = B_TRUE;
76260dc2366fSVenugopal Iyer need_rings = mrp->mrp_ntxrings;
76270dc2366fSVenugopal Iyer } else if (mrp->mrp_ntxrings == 0) {
76280dc2366fSVenugopal Iyer /*
76290dc2366fSVenugopal Iyer * We have asked for a software group.
76300dc2366fSVenugopal Iyer */
76310dc2366fSVenugopal Iyer return (NULL);
76320dc2366fSVenugopal Iyer }
76330dc2366fSVenugopal Iyer }
76340dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
76350dc2366fSVenugopal Iyer /*
76360dc2366fSVenugopal Iyer * The number of rings that the default group can donate.
76370dc2366fSVenugopal Iyer * We need to leave at least one ring - the default ring - in
76380dc2366fSVenugopal Iyer * this group.
76390dc2366fSVenugopal Iyer */
76400dc2366fSVenugopal Iyer defnrings = defgrp->mrg_cur_count - 1;
7641da14cebeSEric Cheng
76420dc2366fSVenugopal Iyer /*
76430dc2366fSVenugopal Iyer * Primary gets default group unless explicitly told not
76440dc2366fSVenugopal Iyer * to (i.e. rings > 0).
76450dc2366fSVenugopal Iyer */
76460dc2366fSVenugopal Iyer if (isprimary && !need_exclgrp)
76470dc2366fSVenugopal Iyer return (NULL);
76480dc2366fSVenugopal Iyer
76490dc2366fSVenugopal Iyer nrings = (mrp->mrp_mask & MRP_TX_RINGS) != 0 ? mrp->mrp_ntxrings : 1;
76500dc2366fSVenugopal Iyer for (i = 0; i < mip->mi_tx_group_count; i++) {
76510dc2366fSVenugopal Iyer grp = &mip->mi_tx_groups[i];
76520dc2366fSVenugopal Iyer if ((grp->mrg_state == MAC_GROUP_STATE_RESERVED) ||
76530dc2366fSVenugopal Iyer (grp->mrg_state == MAC_GROUP_STATE_UNINIT)) {
76540dc2366fSVenugopal Iyer /*
76550dc2366fSVenugopal Iyer * Select a candidate for replacement if we don't
76560dc2366fSVenugopal Iyer * get an exclusive group. A candidate group is one
76570dc2366fSVenugopal Iyer * that didn't ask for an exclusive group, but got
76580dc2366fSVenugopal Iyer * one and it has enough rings (combined with what
76590dc2366fSVenugopal Iyer * the default group can donate) for the new MAC
76600dc2366fSVenugopal Iyer * client.
76610dc2366fSVenugopal Iyer */
76620dc2366fSVenugopal Iyer if (grp->mrg_state == MAC_GROUP_STATE_RESERVED &&
76630dc2366fSVenugopal Iyer candidate_grp == NULL) {
76640dc2366fSVenugopal Iyer gclient = MAC_GROUP_ONLY_CLIENT(grp);
766584de666eSRyan Zezeski VERIFY3P(gclient, !=, NULL);
76660dc2366fSVenugopal Iyer gmrp = MCIP_RESOURCE_PROPS(gclient);
766736f99a58SToomas Soome if (gclient->mci_share == 0 &&
76680dc2366fSVenugopal Iyer (gmrp->mrp_mask & MRP_TX_RINGS) == 0 &&
76690dc2366fSVenugopal Iyer (unspec ||
76700dc2366fSVenugopal Iyer (grp->mrg_cur_count + defnrings) >=
76710dc2366fSVenugopal Iyer need_rings)) {
76720dc2366fSVenugopal Iyer candidate_grp = grp;
76730dc2366fSVenugopal Iyer }
76740dc2366fSVenugopal Iyer }
76750dc2366fSVenugopal Iyer continue;
76760dc2366fSVenugopal Iyer }
76770dc2366fSVenugopal Iyer /*
76780dc2366fSVenugopal Iyer * If the default can't donate let's just walk and
76790dc2366fSVenugopal Iyer * see if someone can vacate a group, so that we have
76800dc2366fSVenugopal Iyer * enough rings for this.
76810dc2366fSVenugopal Iyer */
76820dc2366fSVenugopal Iyer if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC ||
76830dc2366fSVenugopal Iyer nrings <= defnrings) {
76840dc2366fSVenugopal Iyer if (grp->mrg_state == MAC_GROUP_STATE_REGISTERED) {
76850dc2366fSVenugopal Iyer rv = mac_start_group(grp);
76860dc2366fSVenugopal Iyer ASSERT(rv == 0);
76870dc2366fSVenugopal Iyer }
76880dc2366fSVenugopal Iyer break;
76890dc2366fSVenugopal Iyer }
76900dc2366fSVenugopal Iyer }
76910dc2366fSVenugopal Iyer
76920dc2366fSVenugopal Iyer /* The default group */
76930dc2366fSVenugopal Iyer if (i >= mip->mi_tx_group_count) {
76940dc2366fSVenugopal Iyer /*
76950dc2366fSVenugopal Iyer * If we need an exclusive group and have identified a
76960dc2366fSVenugopal Iyer * candidate group we switch the MAC client from the
76970dc2366fSVenugopal Iyer * candidate group to the default group and give the
76980dc2366fSVenugopal Iyer * candidate group to this client.
76990dc2366fSVenugopal Iyer */
77000dc2366fSVenugopal Iyer if (need_exclgrp && candidate_grp != NULL) {
77010dc2366fSVenugopal Iyer /*
770284de666eSRyan Zezeski * Switch the MAC client from the candidate
770384de666eSRyan Zezeski * group to the default group. We know the
770484de666eSRyan Zezeski * candidate_grp came from a reserved group
770584de666eSRyan Zezeski * and thus only has one client.
77060dc2366fSVenugopal Iyer */
77070dc2366fSVenugopal Iyer grp = candidate_grp;
77080dc2366fSVenugopal Iyer gclient = MAC_GROUP_ONLY_CLIENT(grp);
770984de666eSRyan Zezeski VERIFY3P(gclient, !=, NULL);
77100dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)gclient);
77110dc2366fSVenugopal Iyer mac_tx_switch_group(gclient, grp, defgrp);
77120dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)gclient);
77130dc2366fSVenugopal Iyer
77140dc2366fSVenugopal Iyer /*
77150dc2366fSVenugopal Iyer * Give the candidate group with the specified number
77160dc2366fSVenugopal Iyer * of rings to this MAC client.
77170dc2366fSVenugopal Iyer */
77180dc2366fSVenugopal Iyer ASSERT(grp->mrg_state == MAC_GROUP_STATE_REGISTERED);
77190dc2366fSVenugopal Iyer rv = mac_start_group(grp);
77200dc2366fSVenugopal Iyer ASSERT(rv == 0);
77210dc2366fSVenugopal Iyer
77220dc2366fSVenugopal Iyer if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC)
77230dc2366fSVenugopal Iyer return (grp);
77240dc2366fSVenugopal Iyer
77250dc2366fSVenugopal Iyer ASSERT(grp->mrg_cur_count == 0);
77260dc2366fSVenugopal Iyer ASSERT(defgrp->mrg_cur_count > need_rings);
77270dc2366fSVenugopal Iyer
77280dc2366fSVenugopal Iyer err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_TX,
77290dc2366fSVenugopal Iyer defgrp, grp, share, need_rings);
77300dc2366fSVenugopal Iyer if (err == 0) {
77310dc2366fSVenugopal Iyer /*
77320dc2366fSVenugopal Iyer * For a share i_mac_group_allocate_rings gets
77330dc2366fSVenugopal Iyer * the rings from the driver, let's populate
77340dc2366fSVenugopal Iyer * the property for the client now.
77350dc2366fSVenugopal Iyer */
773636f99a58SToomas Soome if (share != 0) {
77370dc2366fSVenugopal Iyer mac_client_set_rings(
77380dc2366fSVenugopal Iyer (mac_client_handle_t)mcip, -1,
77390dc2366fSVenugopal Iyer grp->mrg_cur_count);
77400dc2366fSVenugopal Iyer }
77410dc2366fSVenugopal Iyer mip->mi_tx_group_free--;
77420dc2366fSVenugopal Iyer return (grp);
77430dc2366fSVenugopal Iyer }
77440dc2366fSVenugopal Iyer DTRACE_PROBE3(tx__group__reserve__alloc__rings, char *,
77450dc2366fSVenugopal Iyer mip->mi_name, int, grp->mrg_index, int, err);
77460dc2366fSVenugopal Iyer mac_stop_group(grp);
77470dc2366fSVenugopal Iyer }
77480dc2366fSVenugopal Iyer return (NULL);
77490dc2366fSVenugopal Iyer }
77500dc2366fSVenugopal Iyer /*
77510dc2366fSVenugopal Iyer * We got an exclusive group, but it is not dynamic.
77520dc2366fSVenugopal Iyer */
77530dc2366fSVenugopal Iyer if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) {
77540dc2366fSVenugopal Iyer mip->mi_tx_group_free--;
77550dc2366fSVenugopal Iyer return (grp);
77560dc2366fSVenugopal Iyer }
77570dc2366fSVenugopal Iyer
77580dc2366fSVenugopal Iyer rv = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_TX, defgrp, grp,
77590dc2366fSVenugopal Iyer share, nrings);
77600dc2366fSVenugopal Iyer if (rv != 0) {
77610dc2366fSVenugopal Iyer DTRACE_PROBE3(tx__group__reserve__alloc__rings,
77620dc2366fSVenugopal Iyer char *, mip->mi_name, int, grp->mrg_index, int, rv);
77630dc2366fSVenugopal Iyer mac_stop_group(grp);
77640dc2366fSVenugopal Iyer return (NULL);
77650dc2366fSVenugopal Iyer }
77660dc2366fSVenugopal Iyer /*
77670dc2366fSVenugopal Iyer * For a share i_mac_group_allocate_rings gets the rings from the
77680dc2366fSVenugopal Iyer * driver, let's populate the property for the client now.
77690dc2366fSVenugopal Iyer */
777036f99a58SToomas Soome if (share != 0) {
77710dc2366fSVenugopal Iyer mac_client_set_rings((mac_client_handle_t)mcip, -1,
77720dc2366fSVenugopal Iyer grp->mrg_cur_count);
77730dc2366fSVenugopal Iyer }
77740dc2366fSVenugopal Iyer mip->mi_tx_group_free--;
7775da14cebeSEric Cheng return (grp);
7776da14cebeSEric Cheng }
7777da14cebeSEric Cheng
7778da14cebeSEric Cheng void
mac_release_tx_group(mac_client_impl_t * mcip,mac_group_t * grp)77790dc2366fSVenugopal Iyer mac_release_tx_group(mac_client_impl_t *mcip, mac_group_t *grp)
7780da14cebeSEric Cheng {
77810dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
7782da14cebeSEric Cheng mac_share_handle_t share = mcip->mci_share;
7783da14cebeSEric Cheng mac_ring_t *ring;
77840dc2366fSVenugopal Iyer mac_soft_ring_set_t *srs = MCIP_TX_SRS(mcip);
77850dc2366fSVenugopal Iyer mac_group_t *defgrp;
7786da14cebeSEric Cheng
77870dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
77880dc2366fSVenugopal Iyer if (srs != NULL) {
77890dc2366fSVenugopal Iyer if (srs->srs_soft_ring_count > 0) {
77900dc2366fSVenugopal Iyer for (ring = grp->mrg_rings; ring != NULL;
77910dc2366fSVenugopal Iyer ring = ring->mr_next) {
77920dc2366fSVenugopal Iyer ASSERT(mac_tx_srs_ring_present(srs, ring));
77930dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip,
77940dc2366fSVenugopal Iyer (mac_tx_cookie_t)
77950dc2366fSVenugopal Iyer mac_tx_srs_get_soft_ring(srs, ring));
77960dc2366fSVenugopal Iyer mac_tx_srs_del_ring(srs, ring);
77970dc2366fSVenugopal Iyer }
77980dc2366fSVenugopal Iyer } else {
77990dc2366fSVenugopal Iyer ASSERT(srs->srs_tx.st_arg2 != NULL);
78000dc2366fSVenugopal Iyer srs->srs_tx.st_arg2 = NULL;
78010dc2366fSVenugopal Iyer mac_srs_stat_delete(srs);
78020dc2366fSVenugopal Iyer }
78030dc2366fSVenugopal Iyer }
780436f99a58SToomas Soome if (share != 0)
7805da14cebeSEric Cheng mip->mi_share_capab.ms_sremove(share, grp->mrg_driver);
78060dc2366fSVenugopal Iyer
7807da14cebeSEric Cheng /* move the ring back to the pool */
78080dc2366fSVenugopal Iyer if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
78090dc2366fSVenugopal Iyer while ((ring = grp->mrg_rings) != NULL)
78100dc2366fSVenugopal Iyer (void) mac_group_mov_ring(mip, defgrp, ring);
7811da14cebeSEric Cheng }
7812da14cebeSEric Cheng mac_stop_group(grp);
7813da14cebeSEric Cheng mip->mi_tx_group_free++;
7814da14cebeSEric Cheng }
7815da14cebeSEric Cheng
7816da14cebeSEric Cheng /*
78170dc2366fSVenugopal Iyer * Disassociate a MAC client from a group, i.e go through the rings in the
78180dc2366fSVenugopal Iyer * group and delete all the soft rings tied to them.
78190dc2366fSVenugopal Iyer */
78200dc2366fSVenugopal Iyer static void
mac_tx_dismantle_soft_rings(mac_group_t * fgrp,flow_entry_t * flent)78210dc2366fSVenugopal Iyer mac_tx_dismantle_soft_rings(mac_group_t *fgrp, flow_entry_t *flent)
78220dc2366fSVenugopal Iyer {
78230dc2366fSVenugopal Iyer mac_client_impl_t *mcip = flent->fe_mcip;
78240dc2366fSVenugopal Iyer mac_soft_ring_set_t *tx_srs;
78250dc2366fSVenugopal Iyer mac_srs_tx_t *tx;
78260dc2366fSVenugopal Iyer mac_ring_t *ring;
78270dc2366fSVenugopal Iyer
78280dc2366fSVenugopal Iyer tx_srs = flent->fe_tx_srs;
78290dc2366fSVenugopal Iyer tx = &tx_srs->srs_tx;
78300dc2366fSVenugopal Iyer
78310dc2366fSVenugopal Iyer /* Single ring case we haven't created any soft rings */
78320dc2366fSVenugopal Iyer if (tx->st_mode == SRS_TX_BW || tx->st_mode == SRS_TX_SERIALIZE ||
78330dc2366fSVenugopal Iyer tx->st_mode == SRS_TX_DEFAULT) {
78340dc2366fSVenugopal Iyer tx->st_arg2 = NULL;
78350dc2366fSVenugopal Iyer mac_srs_stat_delete(tx_srs);
78360dc2366fSVenugopal Iyer /* Fanout case, where we have to dismantle the soft rings */
78370dc2366fSVenugopal Iyer } else {
78380dc2366fSVenugopal Iyer for (ring = fgrp->mrg_rings; ring != NULL;
78390dc2366fSVenugopal Iyer ring = ring->mr_next) {
78400dc2366fSVenugopal Iyer ASSERT(mac_tx_srs_ring_present(tx_srs, ring));
78410dc2366fSVenugopal Iyer mac_tx_invoke_callbacks(mcip,
78420dc2366fSVenugopal Iyer (mac_tx_cookie_t)mac_tx_srs_get_soft_ring(tx_srs,
78430dc2366fSVenugopal Iyer ring));
78440dc2366fSVenugopal Iyer mac_tx_srs_del_ring(tx_srs, ring);
78450dc2366fSVenugopal Iyer }
78460dc2366fSVenugopal Iyer ASSERT(tx->st_arg2 == NULL);
78470dc2366fSVenugopal Iyer }
78480dc2366fSVenugopal Iyer }
78490dc2366fSVenugopal Iyer
78500dc2366fSVenugopal Iyer /*
78510dc2366fSVenugopal Iyer * Switch the MAC client from one group to another. This means we need
78520dc2366fSVenugopal Iyer * to remove the MAC client, teardown the SRSs and revert the group state.
78530dc2366fSVenugopal Iyer * Then, we add the client to the destination roup, set the SRSs etc.
78540dc2366fSVenugopal Iyer */
78550dc2366fSVenugopal Iyer void
mac_tx_switch_group(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)78560dc2366fSVenugopal Iyer mac_tx_switch_group(mac_client_impl_t *mcip, mac_group_t *fgrp,
78570dc2366fSVenugopal Iyer mac_group_t *tgrp)
78580dc2366fSVenugopal Iyer {
78590dc2366fSVenugopal Iyer mac_client_impl_t *group_only_mcip;
78600dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
78610dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent;
78620dc2366fSVenugopal Iyer mac_group_t *defgrp;
78630dc2366fSVenugopal Iyer mac_grp_client_t *mgcp;
78640dc2366fSVenugopal Iyer mac_client_impl_t *gmcip;
78650dc2366fSVenugopal Iyer flow_entry_t *gflent;
78660dc2366fSVenugopal Iyer
78670dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
78680dc2366fSVenugopal Iyer ASSERT(fgrp == flent->fe_tx_ring_group);
78690dc2366fSVenugopal Iyer
78700dc2366fSVenugopal Iyer if (fgrp == defgrp) {
78710dc2366fSVenugopal Iyer /*
78720dc2366fSVenugopal Iyer * If this is the primary we need to find any VLANs on
78730dc2366fSVenugopal Iyer * the primary and move them too.
78740dc2366fSVenugopal Iyer */
78750dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, mcip);
78760dc2366fSVenugopal Iyer mac_tx_dismantle_soft_rings(fgrp, flent);
787784de666eSRyan Zezeski if (mac_check_macaddr_shared(mcip->mci_unicast)) {
78780dc2366fSVenugopal Iyer mgcp = fgrp->mrg_clients;
78790dc2366fSVenugopal Iyer while (mgcp != NULL) {
78800dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
78810dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
78820dc2366fSVenugopal Iyer if (mcip->mci_unicast != gmcip->mci_unicast)
78830dc2366fSVenugopal Iyer continue;
78840dc2366fSVenugopal Iyer mac_tx_client_quiesce(
78850dc2366fSVenugopal Iyer (mac_client_handle_t)gmcip);
78860dc2366fSVenugopal Iyer
78870dc2366fSVenugopal Iyer gflent = gmcip->mci_flent;
78880dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, gmcip);
78890dc2366fSVenugopal Iyer mac_tx_dismantle_soft_rings(fgrp, gflent);
78900dc2366fSVenugopal Iyer
78910dc2366fSVenugopal Iyer mac_group_add_client(tgrp, gmcip);
78920dc2366fSVenugopal Iyer gflent->fe_tx_ring_group = tgrp;
78930dc2366fSVenugopal Iyer /* We could directly set this to SHARED */
78940dc2366fSVenugopal Iyer tgrp->mrg_state = mac_group_next_state(tgrp,
78950dc2366fSVenugopal Iyer &group_only_mcip, defgrp, B_FALSE);
78960dc2366fSVenugopal Iyer
78970dc2366fSVenugopal Iyer mac_tx_srs_group_setup(gmcip, gflent,
78980dc2366fSVenugopal Iyer SRST_LINK);
78990dc2366fSVenugopal Iyer mac_fanout_setup(gmcip, gflent,
79000dc2366fSVenugopal Iyer MCIP_RESOURCE_PROPS(gmcip), mac_rx_deliver,
79010dc2366fSVenugopal Iyer gmcip, NULL, NULL);
79020dc2366fSVenugopal Iyer
79030dc2366fSVenugopal Iyer mac_tx_client_restart(
79040dc2366fSVenugopal Iyer (mac_client_handle_t)gmcip);
79050dc2366fSVenugopal Iyer }
79060dc2366fSVenugopal Iyer }
79070dc2366fSVenugopal Iyer if (MAC_GROUP_NO_CLIENT(fgrp)) {
79080dc2366fSVenugopal Iyer mac_ring_t *ring;
79090dc2366fSVenugopal Iyer int cnt;
79100dc2366fSVenugopal Iyer int ringcnt;
79110dc2366fSVenugopal Iyer
79120dc2366fSVenugopal Iyer fgrp->mrg_state = MAC_GROUP_STATE_REGISTERED;
79130dc2366fSVenugopal Iyer /*
79140dc2366fSVenugopal Iyer * Additionally, we also need to stop all
79150dc2366fSVenugopal Iyer * the rings in the default group, except
79160dc2366fSVenugopal Iyer * the default ring. The reason being
79170dc2366fSVenugopal Iyer * this group won't be released since it is
79180dc2366fSVenugopal Iyer * the default group, so the rings won't
79190dc2366fSVenugopal Iyer * be stopped otherwise.
79200dc2366fSVenugopal Iyer */
79210dc2366fSVenugopal Iyer ringcnt = fgrp->mrg_cur_count;
79220dc2366fSVenugopal Iyer ring = fgrp->mrg_rings;
79230dc2366fSVenugopal Iyer for (cnt = 0; cnt < ringcnt; cnt++) {
79240dc2366fSVenugopal Iyer if (ring->mr_state == MR_INUSE &&
79250dc2366fSVenugopal Iyer ring !=
79260dc2366fSVenugopal Iyer (mac_ring_t *)mip->mi_default_tx_ring) {
79270dc2366fSVenugopal Iyer mac_stop_ring(ring);
79280dc2366fSVenugopal Iyer ring->mr_flag = 0;
79290dc2366fSVenugopal Iyer }
79300dc2366fSVenugopal Iyer ring = ring->mr_next;
79310dc2366fSVenugopal Iyer }
79320dc2366fSVenugopal Iyer } else if (MAC_GROUP_ONLY_CLIENT(fgrp) != NULL) {
79330dc2366fSVenugopal Iyer fgrp->mrg_state = MAC_GROUP_STATE_RESERVED;
79340dc2366fSVenugopal Iyer } else {
79350dc2366fSVenugopal Iyer ASSERT(fgrp->mrg_state == MAC_GROUP_STATE_SHARED);
79360dc2366fSVenugopal Iyer }
79370dc2366fSVenugopal Iyer } else {
79380dc2366fSVenugopal Iyer /*
79390dc2366fSVenugopal Iyer * We could have VLANs sharing the non-default group with
79400dc2366fSVenugopal Iyer * the primary.
79410dc2366fSVenugopal Iyer */
79420dc2366fSVenugopal Iyer mgcp = fgrp->mrg_clients;
79430dc2366fSVenugopal Iyer while (mgcp != NULL) {
79440dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
79450dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
79460dc2366fSVenugopal Iyer if (gmcip == mcip)
79470dc2366fSVenugopal Iyer continue;
79480dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)gmcip);
79490dc2366fSVenugopal Iyer gflent = gmcip->mci_flent;
79500dc2366fSVenugopal Iyer
79510dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, gmcip);
79520dc2366fSVenugopal Iyer mac_tx_dismantle_soft_rings(fgrp, gflent);
79530dc2366fSVenugopal Iyer
79540dc2366fSVenugopal Iyer mac_group_add_client(tgrp, gmcip);
79550dc2366fSVenugopal Iyer gflent->fe_tx_ring_group = tgrp;
79560dc2366fSVenugopal Iyer /* We could directly set this to SHARED */
79570dc2366fSVenugopal Iyer tgrp->mrg_state = mac_group_next_state(tgrp,
79580dc2366fSVenugopal Iyer &group_only_mcip, defgrp, B_FALSE);
79590dc2366fSVenugopal Iyer mac_tx_srs_group_setup(gmcip, gflent, SRST_LINK);
79600dc2366fSVenugopal Iyer mac_fanout_setup(gmcip, gflent,
79610dc2366fSVenugopal Iyer MCIP_RESOURCE_PROPS(gmcip), mac_rx_deliver,
79620dc2366fSVenugopal Iyer gmcip, NULL, NULL);
79630dc2366fSVenugopal Iyer
79640dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)gmcip);
79650dc2366fSVenugopal Iyer }
79660dc2366fSVenugopal Iyer mac_group_remove_client(fgrp, mcip);
79670dc2366fSVenugopal Iyer mac_release_tx_group(mcip, fgrp);
79680dc2366fSVenugopal Iyer fgrp->mrg_state = MAC_GROUP_STATE_REGISTERED;
79690dc2366fSVenugopal Iyer }
79700dc2366fSVenugopal Iyer
79710dc2366fSVenugopal Iyer /* Add it to the tgroup */
79720dc2366fSVenugopal Iyer mac_group_add_client(tgrp, mcip);
79730dc2366fSVenugopal Iyer flent->fe_tx_ring_group = tgrp;
79740dc2366fSVenugopal Iyer tgrp->mrg_state = mac_group_next_state(tgrp, &group_only_mcip,
79750dc2366fSVenugopal Iyer defgrp, B_FALSE);
79760dc2366fSVenugopal Iyer
79770dc2366fSVenugopal Iyer mac_tx_srs_group_setup(mcip, flent, SRST_LINK);
79780dc2366fSVenugopal Iyer mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
79790dc2366fSVenugopal Iyer mac_rx_deliver, mcip, NULL, NULL);
79800dc2366fSVenugopal Iyer }
79810dc2366fSVenugopal Iyer
79820dc2366fSVenugopal Iyer /*
7983da14cebeSEric Cheng * This is a 1-time control path activity initiated by the client (IP).
7984da14cebeSEric Cheng * The mac perimeter protects against other simultaneous control activities,
7985da14cebeSEric Cheng * for example an ioctl that attempts to change the degree of fanout and
7986da14cebeSEric Cheng * increase or decrease the number of softrings associated with this Tx SRS.
7987da14cebeSEric Cheng */
7988da14cebeSEric Cheng static mac_tx_notify_cb_t *
mac_client_tx_notify_add(mac_client_impl_t * mcip,mac_tx_notify_t notify,void * arg)7989da14cebeSEric Cheng mac_client_tx_notify_add(mac_client_impl_t *mcip,
7990da14cebeSEric Cheng mac_tx_notify_t notify, void *arg)
7991da14cebeSEric Cheng {
7992da14cebeSEric Cheng mac_cb_info_t *mcbi;
7993da14cebeSEric Cheng mac_tx_notify_cb_t *mtnfp;
7994da14cebeSEric Cheng
7995da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
7996da14cebeSEric Cheng
7997da14cebeSEric Cheng mtnfp = kmem_zalloc(sizeof (mac_tx_notify_cb_t), KM_SLEEP);
7998da14cebeSEric Cheng mtnfp->mtnf_fn = notify;
7999da14cebeSEric Cheng mtnfp->mtnf_arg = arg;
8000da14cebeSEric Cheng mtnfp->mtnf_link.mcb_objp = mtnfp;
8001da14cebeSEric Cheng mtnfp->mtnf_link.mcb_objsize = sizeof (mac_tx_notify_cb_t);
8002da14cebeSEric Cheng mtnfp->mtnf_link.mcb_flags = MCB_TX_NOTIFY_CB_T;
8003da14cebeSEric Cheng
8004da14cebeSEric Cheng mcbi = &mcip->mci_tx_notify_cb_info;
8005da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp);
8006da14cebeSEric Cheng mac_callback_add(mcbi, &mcip->mci_tx_notify_cb_list, &mtnfp->mtnf_link);
8007da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp);
8008da14cebeSEric Cheng return (mtnfp);
8009da14cebeSEric Cheng }
8010da14cebeSEric Cheng
8011da14cebeSEric Cheng static void
mac_client_tx_notify_remove(mac_client_impl_t * mcip,mac_tx_notify_cb_t * mtnfp)8012da14cebeSEric Cheng mac_client_tx_notify_remove(mac_client_impl_t *mcip, mac_tx_notify_cb_t *mtnfp)
8013da14cebeSEric Cheng {
8014da14cebeSEric Cheng mac_cb_info_t *mcbi;
8015da14cebeSEric Cheng mac_cb_t **cblist;
8016da14cebeSEric Cheng
8017da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
8018da14cebeSEric Cheng
8019da14cebeSEric Cheng if (!mac_callback_find(&mcip->mci_tx_notify_cb_info,
8020da14cebeSEric Cheng &mcip->mci_tx_notify_cb_list, &mtnfp->mtnf_link)) {
8021da14cebeSEric Cheng cmn_err(CE_WARN,
8022da14cebeSEric Cheng "mac_client_tx_notify_remove: callback not "
8023da14cebeSEric Cheng "found, mcip 0x%p mtnfp 0x%p", (void *)mcip, (void *)mtnfp);
8024da14cebeSEric Cheng return;
8025da14cebeSEric Cheng }
8026da14cebeSEric Cheng
8027da14cebeSEric Cheng mcbi = &mcip->mci_tx_notify_cb_info;
8028da14cebeSEric Cheng cblist = &mcip->mci_tx_notify_cb_list;
8029da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp);
8030da14cebeSEric Cheng if (mac_callback_remove(mcbi, cblist, &mtnfp->mtnf_link))
8031da14cebeSEric Cheng kmem_free(mtnfp, sizeof (mac_tx_notify_cb_t));
8032da14cebeSEric Cheng else
8033da14cebeSEric Cheng mac_callback_remove_wait(&mcip->mci_tx_notify_cb_info);
8034da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp);
8035da14cebeSEric Cheng }
8036da14cebeSEric Cheng
8037da14cebeSEric Cheng /*
8038da14cebeSEric Cheng * mac_client_tx_notify():
8039da14cebeSEric Cheng * call to add and remove flow control callback routine.
8040da14cebeSEric Cheng */
8041da14cebeSEric Cheng mac_tx_notify_handle_t
mac_client_tx_notify(mac_client_handle_t mch,mac_tx_notify_t callb_func,void * ptr)8042da14cebeSEric Cheng mac_client_tx_notify(mac_client_handle_t mch, mac_tx_notify_t callb_func,
8043da14cebeSEric Cheng void *ptr)
8044da14cebeSEric Cheng {
8045da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
8046da14cebeSEric Cheng mac_tx_notify_cb_t *mtnfp = NULL;
8047da14cebeSEric Cheng
8048da14cebeSEric Cheng i_mac_perim_enter(mcip->mci_mip);
8049da14cebeSEric Cheng
8050da14cebeSEric Cheng if (callb_func != NULL) {
8051da14cebeSEric Cheng /* Add a notify callback */
8052da14cebeSEric Cheng mtnfp = mac_client_tx_notify_add(mcip, callb_func, ptr);
8053da14cebeSEric Cheng } else {
8054da14cebeSEric Cheng mac_client_tx_notify_remove(mcip, (mac_tx_notify_cb_t *)ptr);
8055da14cebeSEric Cheng }
8056da14cebeSEric Cheng i_mac_perim_exit(mcip->mci_mip);
8057da14cebeSEric Cheng
8058da14cebeSEric Cheng return ((mac_tx_notify_handle_t)mtnfp);
8059da14cebeSEric Cheng }
80604eaa4710SRishi Srivatsavai
80614eaa4710SRishi Srivatsavai void
mac_bridge_vectors(mac_bridge_tx_t txf,mac_bridge_rx_t rxf,mac_bridge_ref_t reff,mac_bridge_ls_t lsf)80624eaa4710SRishi Srivatsavai mac_bridge_vectors(mac_bridge_tx_t txf, mac_bridge_rx_t rxf,
80634eaa4710SRishi Srivatsavai mac_bridge_ref_t reff, mac_bridge_ls_t lsf)
80644eaa4710SRishi Srivatsavai {
80654eaa4710SRishi Srivatsavai mac_bridge_tx_cb = txf;
80664eaa4710SRishi Srivatsavai mac_bridge_rx_cb = rxf;
80674eaa4710SRishi Srivatsavai mac_bridge_ref_cb = reff;
80684eaa4710SRishi Srivatsavai mac_bridge_ls_cb = lsf;
80694eaa4710SRishi Srivatsavai }
80704eaa4710SRishi Srivatsavai
80714eaa4710SRishi Srivatsavai int
mac_bridge_set(mac_handle_t mh,mac_handle_t link)80724eaa4710SRishi Srivatsavai mac_bridge_set(mac_handle_t mh, mac_handle_t link)
80734eaa4710SRishi Srivatsavai {
80744eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh;
80754eaa4710SRishi Srivatsavai int retv;
80764eaa4710SRishi Srivatsavai
80774eaa4710SRishi Srivatsavai mutex_enter(&mip->mi_bridge_lock);
80784eaa4710SRishi Srivatsavai if (mip->mi_bridge_link == NULL) {
80794eaa4710SRishi Srivatsavai mip->mi_bridge_link = link;
80804eaa4710SRishi Srivatsavai retv = 0;
80814eaa4710SRishi Srivatsavai } else {
80824eaa4710SRishi Srivatsavai retv = EBUSY;
80834eaa4710SRishi Srivatsavai }
80844eaa4710SRishi Srivatsavai mutex_exit(&mip->mi_bridge_lock);
80854eaa4710SRishi Srivatsavai if (retv == 0) {
80864eaa4710SRishi Srivatsavai mac_poll_state_change(mh, B_FALSE);
80874eaa4710SRishi Srivatsavai mac_capab_update(mh);
80884eaa4710SRishi Srivatsavai }
80894eaa4710SRishi Srivatsavai return (retv);
80904eaa4710SRishi Srivatsavai }
80914eaa4710SRishi Srivatsavai
80924eaa4710SRishi Srivatsavai /*
80934eaa4710SRishi Srivatsavai * Disable bridging on the indicated link.
80944eaa4710SRishi Srivatsavai */
80954eaa4710SRishi Srivatsavai void
mac_bridge_clear(mac_handle_t mh,mac_handle_t link)80964eaa4710SRishi Srivatsavai mac_bridge_clear(mac_handle_t mh, mac_handle_t link)
80974eaa4710SRishi Srivatsavai {
80984eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh;
80994eaa4710SRishi Srivatsavai
81004eaa4710SRishi Srivatsavai mutex_enter(&mip->mi_bridge_lock);
81014eaa4710SRishi Srivatsavai ASSERT(mip->mi_bridge_link == link);
81024eaa4710SRishi Srivatsavai mip->mi_bridge_link = NULL;
81034eaa4710SRishi Srivatsavai mutex_exit(&mip->mi_bridge_lock);
81044eaa4710SRishi Srivatsavai mac_poll_state_change(mh, B_TRUE);
81054eaa4710SRishi Srivatsavai mac_capab_update(mh);
81064eaa4710SRishi Srivatsavai }
81074eaa4710SRishi Srivatsavai
81084eaa4710SRishi Srivatsavai void
mac_no_active(mac_handle_t mh)81094eaa4710SRishi Srivatsavai mac_no_active(mac_handle_t mh)
81104eaa4710SRishi Srivatsavai {
81114eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh;
81124eaa4710SRishi Srivatsavai
81134eaa4710SRishi Srivatsavai i_mac_perim_enter(mip);
81144eaa4710SRishi Srivatsavai mip->mi_state_flags |= MIS_NO_ACTIVE;
81154eaa4710SRishi Srivatsavai i_mac_perim_exit(mip);
81164eaa4710SRishi Srivatsavai }
81170dc2366fSVenugopal Iyer
81180dc2366fSVenugopal Iyer /*
81190dc2366fSVenugopal Iyer * Walk the primary VLAN clients whenever the primary's rings property
81200dc2366fSVenugopal Iyer * changes and update the mac_resource_props_t for the VLAN's client.
81210dc2366fSVenugopal Iyer * We need to do this since we don't support setting these properties
81220dc2366fSVenugopal Iyer * on the primary's VLAN clients, but the VLAN clients have to
812384de666eSRyan Zezeski * follow the primary w.r.t the rings property.
81240dc2366fSVenugopal Iyer */
81250dc2366fSVenugopal Iyer void
mac_set_prim_vlan_rings(mac_impl_t * mip,mac_resource_props_t * mrp)81260dc2366fSVenugopal Iyer mac_set_prim_vlan_rings(mac_impl_t *mip, mac_resource_props_t *mrp)
81270dc2366fSVenugopal Iyer {
81280dc2366fSVenugopal Iyer mac_client_impl_t *vmcip;
81290dc2366fSVenugopal Iyer mac_resource_props_t *vmrp;
81300dc2366fSVenugopal Iyer
81310dc2366fSVenugopal Iyer for (vmcip = mip->mi_clients_list; vmcip != NULL;
81320dc2366fSVenugopal Iyer vmcip = vmcip->mci_client_next) {
81330dc2366fSVenugopal Iyer if (!(vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) ||
81340dc2366fSVenugopal Iyer mac_client_vid((mac_client_handle_t)vmcip) ==
81350dc2366fSVenugopal Iyer VLAN_ID_NONE) {
81360dc2366fSVenugopal Iyer continue;
81370dc2366fSVenugopal Iyer }
81380dc2366fSVenugopal Iyer vmrp = MCIP_RESOURCE_PROPS(vmcip);
81390dc2366fSVenugopal Iyer
81400dc2366fSVenugopal Iyer vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
81410dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS)
81420dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_RX_RINGS;
81430dc2366fSVenugopal Iyer else if (vmrp->mrp_mask & MRP_RX_RINGS)
81440dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_RX_RINGS;
81450dc2366fSVenugopal Iyer
81460dc2366fSVenugopal Iyer vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
81470dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TX_RINGS)
81480dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_TX_RINGS;
81490dc2366fSVenugopal Iyer else if (vmrp->mrp_mask & MRP_TX_RINGS)
81500dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_TX_RINGS;
81510dc2366fSVenugopal Iyer
81520dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC)
81530dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
81540dc2366fSVenugopal Iyer else
81550dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
81560dc2366fSVenugopal Iyer
81570dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC)
81580dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
81590dc2366fSVenugopal Iyer else
81600dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
81610dc2366fSVenugopal Iyer }
81620dc2366fSVenugopal Iyer }
81630dc2366fSVenugopal Iyer
81640dc2366fSVenugopal Iyer /*
81650dc2366fSVenugopal Iyer * We are adding or removing ring(s) from a group. The source for taking
81660dc2366fSVenugopal Iyer * rings is the default group. The destination for giving rings back is
81670dc2366fSVenugopal Iyer * the default group.
81680dc2366fSVenugopal Iyer */
81690dc2366fSVenugopal Iyer int
mac_group_ring_modify(mac_client_impl_t * mcip,mac_group_t * group,mac_group_t * defgrp)81700dc2366fSVenugopal Iyer mac_group_ring_modify(mac_client_impl_t *mcip, mac_group_t *group,
81710dc2366fSVenugopal Iyer mac_group_t *defgrp)
81720dc2366fSVenugopal Iyer {
81730dc2366fSVenugopal Iyer mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
81740dc2366fSVenugopal Iyer uint_t modify;
81750dc2366fSVenugopal Iyer int count;
81760dc2366fSVenugopal Iyer mac_ring_t *ring;
81770dc2366fSVenugopal Iyer mac_ring_t *next;
81780dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
81790dc2366fSVenugopal Iyer mac_ring_t **rings;
81800dc2366fSVenugopal Iyer uint_t ringcnt;
81810dc2366fSVenugopal Iyer int i = 0;
81820dc2366fSVenugopal Iyer boolean_t rx_group = group->mrg_type == MAC_RING_TYPE_RX;
81830dc2366fSVenugopal Iyer int start;
81840dc2366fSVenugopal Iyer int end;
81850dc2366fSVenugopal Iyer mac_group_t *tgrp;
81860dc2366fSVenugopal Iyer int j;
81870dc2366fSVenugopal Iyer int rv = 0;
81880dc2366fSVenugopal Iyer
81890dc2366fSVenugopal Iyer /*
81900dc2366fSVenugopal Iyer * If we are asked for just a group, we give 1 ring, else
81910dc2366fSVenugopal Iyer * the specified number of rings.
81920dc2366fSVenugopal Iyer */
81930dc2366fSVenugopal Iyer if (rx_group) {
81940dc2366fSVenugopal Iyer ringcnt = (mrp->mrp_mask & MRP_RXRINGS_UNSPEC) ? 1:
81950dc2366fSVenugopal Iyer mrp->mrp_nrxrings;
81960dc2366fSVenugopal Iyer } else {
81970dc2366fSVenugopal Iyer ringcnt = (mrp->mrp_mask & MRP_TXRINGS_UNSPEC) ? 1:
81980dc2366fSVenugopal Iyer mrp->mrp_ntxrings;
81990dc2366fSVenugopal Iyer }
82000dc2366fSVenugopal Iyer
82010dc2366fSVenugopal Iyer /* don't allow modifying rings for a share for now. */
82026895f6f4SToomas Soome ASSERT(mcip->mci_share == 0);
82030dc2366fSVenugopal Iyer
82040dc2366fSVenugopal Iyer if (ringcnt == group->mrg_cur_count)
82050dc2366fSVenugopal Iyer return (0);
82060dc2366fSVenugopal Iyer
82070dc2366fSVenugopal Iyer if (group->mrg_cur_count > ringcnt) {
82080dc2366fSVenugopal Iyer modify = group->mrg_cur_count - ringcnt;
82090dc2366fSVenugopal Iyer if (rx_group) {
82100dc2366fSVenugopal Iyer if (mip->mi_rx_donor_grp == group) {
82110dc2366fSVenugopal Iyer ASSERT(mac_is_primary_client(mcip));
82120dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = defgrp;
82130dc2366fSVenugopal Iyer } else {
82140dc2366fSVenugopal Iyer defgrp = mip->mi_rx_donor_grp;
82150dc2366fSVenugopal Iyer }
82160dc2366fSVenugopal Iyer }
82170dc2366fSVenugopal Iyer ring = group->mrg_rings;
82180dc2366fSVenugopal Iyer rings = kmem_alloc(modify * sizeof (mac_ring_handle_t),
82190dc2366fSVenugopal Iyer KM_SLEEP);
82200dc2366fSVenugopal Iyer j = 0;
82210dc2366fSVenugopal Iyer for (count = 0; count < modify; count++) {
82220dc2366fSVenugopal Iyer next = ring->mr_next;
82230dc2366fSVenugopal Iyer rv = mac_group_mov_ring(mip, defgrp, ring);
82240dc2366fSVenugopal Iyer if (rv != 0) {
82250dc2366fSVenugopal Iyer /* cleanup on failure */
82260dc2366fSVenugopal Iyer for (j = 0; j < count; j++) {
82270dc2366fSVenugopal Iyer (void) mac_group_mov_ring(mip, group,
82280dc2366fSVenugopal Iyer rings[j]);
82290dc2366fSVenugopal Iyer }
82300dc2366fSVenugopal Iyer break;
82310dc2366fSVenugopal Iyer }
82320dc2366fSVenugopal Iyer rings[j++] = ring;
82330dc2366fSVenugopal Iyer ring = next;
82340dc2366fSVenugopal Iyer }
82350dc2366fSVenugopal Iyer kmem_free(rings, modify * sizeof (mac_ring_handle_t));
82360dc2366fSVenugopal Iyer return (rv);
82370dc2366fSVenugopal Iyer }
82380dc2366fSVenugopal Iyer if (ringcnt >= MAX_RINGS_PER_GROUP)
82390dc2366fSVenugopal Iyer return (EINVAL);
82400dc2366fSVenugopal Iyer
82410dc2366fSVenugopal Iyer modify = ringcnt - group->mrg_cur_count;
82420dc2366fSVenugopal Iyer
82430dc2366fSVenugopal Iyer if (rx_group) {
82440dc2366fSVenugopal Iyer if (group != mip->mi_rx_donor_grp)
82450dc2366fSVenugopal Iyer defgrp = mip->mi_rx_donor_grp;
82460dc2366fSVenugopal Iyer else
82470dc2366fSVenugopal Iyer /*
82480dc2366fSVenugopal Iyer * This is the donor group with all the remaining
82490dc2366fSVenugopal Iyer * rings. Default group now gets to be the donor
82500dc2366fSVenugopal Iyer */
82510dc2366fSVenugopal Iyer mip->mi_rx_donor_grp = defgrp;
82520dc2366fSVenugopal Iyer start = 1;
82530dc2366fSVenugopal Iyer end = mip->mi_rx_group_count;
82540dc2366fSVenugopal Iyer } else {
82550dc2366fSVenugopal Iyer start = 0;
82560dc2366fSVenugopal Iyer end = mip->mi_tx_group_count - 1;
82570dc2366fSVenugopal Iyer }
82580dc2366fSVenugopal Iyer /*
82590dc2366fSVenugopal Iyer * If the default doesn't have any rings, lets see if we can
82600dc2366fSVenugopal Iyer * take rings given to an h/w client that doesn't need it.
82610dc2366fSVenugopal Iyer * For now, we just see if there is any one client that can donate
82620dc2366fSVenugopal Iyer * all the required rings.
82630dc2366fSVenugopal Iyer */
82640dc2366fSVenugopal Iyer if (defgrp->mrg_cur_count < (modify + 1)) {
82650dc2366fSVenugopal Iyer for (i = start; i < end; i++) {
82660dc2366fSVenugopal Iyer if (rx_group) {
82670dc2366fSVenugopal Iyer tgrp = &mip->mi_rx_groups[i];
82680dc2366fSVenugopal Iyer if (tgrp == group || tgrp->mrg_state <
82690dc2366fSVenugopal Iyer MAC_GROUP_STATE_RESERVED) {
82700dc2366fSVenugopal Iyer continue;
82710dc2366fSVenugopal Iyer }
827284de666eSRyan Zezeski if (i_mac_clients_hw(tgrp, MRP_RX_RINGS))
82730dc2366fSVenugopal Iyer continue;
827484de666eSRyan Zezeski mcip = tgrp->mrg_clients->mgc_client;
827584de666eSRyan Zezeski VERIFY3P(mcip, !=, NULL);
82760dc2366fSVenugopal Iyer if ((tgrp->mrg_cur_count +
82770dc2366fSVenugopal Iyer defgrp->mrg_cur_count) < (modify + 1)) {
82780dc2366fSVenugopal Iyer continue;
82790dc2366fSVenugopal Iyer }
82800dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, tgrp,
82810dc2366fSVenugopal Iyer defgrp) != 0) {
82820dc2366fSVenugopal Iyer return (ENOSPC);
82830dc2366fSVenugopal Iyer }
82840dc2366fSVenugopal Iyer } else {
82850dc2366fSVenugopal Iyer tgrp = &mip->mi_tx_groups[i];
82860dc2366fSVenugopal Iyer if (tgrp == group || tgrp->mrg_state <
82870dc2366fSVenugopal Iyer MAC_GROUP_STATE_RESERVED) {
82880dc2366fSVenugopal Iyer continue;
82890dc2366fSVenugopal Iyer }
829084de666eSRyan Zezeski if (i_mac_clients_hw(tgrp, MRP_TX_RINGS))
82910dc2366fSVenugopal Iyer continue;
829284de666eSRyan Zezeski mcip = tgrp->mrg_clients->mgc_client;
829384de666eSRyan Zezeski VERIFY3P(mcip, !=, NULL);
82940dc2366fSVenugopal Iyer if ((tgrp->mrg_cur_count +
82950dc2366fSVenugopal Iyer defgrp->mrg_cur_count) < (modify + 1)) {
82960dc2366fSVenugopal Iyer continue;
82970dc2366fSVenugopal Iyer }
82980dc2366fSVenugopal Iyer /* OK, we can switch this to s/w */
82990dc2366fSVenugopal Iyer mac_tx_client_quiesce(
83000dc2366fSVenugopal Iyer (mac_client_handle_t)mcip);
83010dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, tgrp, defgrp);
83020dc2366fSVenugopal Iyer mac_tx_client_restart(
83030dc2366fSVenugopal Iyer (mac_client_handle_t)mcip);
83040dc2366fSVenugopal Iyer }
83050dc2366fSVenugopal Iyer }
83060dc2366fSVenugopal Iyer if (defgrp->mrg_cur_count < (modify + 1))
83070dc2366fSVenugopal Iyer return (ENOSPC);
83080dc2366fSVenugopal Iyer }
83090dc2366fSVenugopal Iyer if ((rv = i_mac_group_allocate_rings(mip, group->mrg_type, defgrp,
83100dc2366fSVenugopal Iyer group, mcip->mci_share, modify)) != 0) {
83110dc2366fSVenugopal Iyer return (rv);
83120dc2366fSVenugopal Iyer }
83130dc2366fSVenugopal Iyer return (0);
83140dc2366fSVenugopal Iyer }
83150dc2366fSVenugopal Iyer
83160dc2366fSVenugopal Iyer /*
83170dc2366fSVenugopal Iyer * Given the poolname in mac_resource_props, find the cpupart
83180dc2366fSVenugopal Iyer * that is associated with this pool. The cpupart will be used
83190dc2366fSVenugopal Iyer * later for finding the cpus to be bound to the networking threads.
83200dc2366fSVenugopal Iyer *
83210dc2366fSVenugopal Iyer * use_default is set B_TRUE if pools are enabled and pool_default
83220dc2366fSVenugopal Iyer * is returned. This avoids a 2nd lookup to set the poolname
83230dc2366fSVenugopal Iyer * for pool-effective.
83240dc2366fSVenugopal Iyer *
83250dc2366fSVenugopal Iyer * returns:
83260dc2366fSVenugopal Iyer *
83270dc2366fSVenugopal Iyer * NULL - pools are disabled or if the 'cpus' property is set.
83280dc2366fSVenugopal Iyer * cpupart of pool_default - pools are enabled and the pool
83290dc2366fSVenugopal Iyer * is not available or poolname is blank
83300dc2366fSVenugopal Iyer * cpupart of named pool - pools are enabled and the pool
83310dc2366fSVenugopal Iyer * is available.
83320dc2366fSVenugopal Iyer */
83330dc2366fSVenugopal Iyer cpupart_t *
mac_pset_find(mac_resource_props_t * mrp,boolean_t * use_default)83340dc2366fSVenugopal Iyer mac_pset_find(mac_resource_props_t *mrp, boolean_t *use_default)
83350dc2366fSVenugopal Iyer {
83360dc2366fSVenugopal Iyer pool_t *pool;
83370dc2366fSVenugopal Iyer cpupart_t *cpupart;
83380dc2366fSVenugopal Iyer
83390dc2366fSVenugopal Iyer *use_default = B_FALSE;
83400dc2366fSVenugopal Iyer
83410dc2366fSVenugopal Iyer /* CPUs property is set */
83420dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_CPUS)
83430dc2366fSVenugopal Iyer return (NULL);
83440dc2366fSVenugopal Iyer
83450dc2366fSVenugopal Iyer ASSERT(pool_lock_held());
83460dc2366fSVenugopal Iyer
83470dc2366fSVenugopal Iyer /* Pools are disabled, no pset */
83480dc2366fSVenugopal Iyer if (pool_state == POOL_DISABLED)
83490dc2366fSVenugopal Iyer return (NULL);
83500dc2366fSVenugopal Iyer
83510dc2366fSVenugopal Iyer /* Pools property is set */
83520dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_POOL) {
83530dc2366fSVenugopal Iyer if ((pool = pool_lookup_pool_by_name(mrp->mrp_pool)) == NULL) {
83540dc2366fSVenugopal Iyer /* Pool not found */
83550dc2366fSVenugopal Iyer DTRACE_PROBE1(mac_pset_find_no_pool, char *,
83560dc2366fSVenugopal Iyer mrp->mrp_pool);
83570dc2366fSVenugopal Iyer *use_default = B_TRUE;
83580dc2366fSVenugopal Iyer pool = pool_default;
83590dc2366fSVenugopal Iyer }
83600dc2366fSVenugopal Iyer /* Pools property is not set */
83610dc2366fSVenugopal Iyer } else {
83620dc2366fSVenugopal Iyer *use_default = B_TRUE;
83630dc2366fSVenugopal Iyer pool = pool_default;
83640dc2366fSVenugopal Iyer }
83650dc2366fSVenugopal Iyer
83660dc2366fSVenugopal Iyer /* Find the CPU pset that corresponds to the pool */
83670dc2366fSVenugopal Iyer mutex_enter(&cpu_lock);
83680dc2366fSVenugopal Iyer if ((cpupart = cpupart_find(pool->pool_pset->pset_id)) == NULL) {
83690dc2366fSVenugopal Iyer DTRACE_PROBE1(mac_find_pset_no_pset, psetid_t,
83700dc2366fSVenugopal Iyer pool->pool_pset->pset_id);
83710dc2366fSVenugopal Iyer }
83720dc2366fSVenugopal Iyer mutex_exit(&cpu_lock);
83730dc2366fSVenugopal Iyer
83740dc2366fSVenugopal Iyer return (cpupart);
83750dc2366fSVenugopal Iyer }
83760dc2366fSVenugopal Iyer
83770dc2366fSVenugopal Iyer void
mac_set_pool_effective(boolean_t use_default,cpupart_t * cpupart,mac_resource_props_t * mrp,mac_resource_props_t * emrp)83780dc2366fSVenugopal Iyer mac_set_pool_effective(boolean_t use_default, cpupart_t *cpupart,
83790dc2366fSVenugopal Iyer mac_resource_props_t *mrp, mac_resource_props_t *emrp)
83800dc2366fSVenugopal Iyer {
83810dc2366fSVenugopal Iyer ASSERT(pool_lock_held());
83820dc2366fSVenugopal Iyer
83830dc2366fSVenugopal Iyer if (cpupart != NULL) {
83840dc2366fSVenugopal Iyer emrp->mrp_mask |= MRP_POOL;
83850dc2366fSVenugopal Iyer if (use_default) {
83860dc2366fSVenugopal Iyer (void) strcpy(emrp->mrp_pool,
83870dc2366fSVenugopal Iyer "pool_default");
83880dc2366fSVenugopal Iyer } else {
83890dc2366fSVenugopal Iyer ASSERT(strlen(mrp->mrp_pool) != 0);
83900dc2366fSVenugopal Iyer (void) strcpy(emrp->mrp_pool,
83910dc2366fSVenugopal Iyer mrp->mrp_pool);
83920dc2366fSVenugopal Iyer }
83930dc2366fSVenugopal Iyer } else {
83940dc2366fSVenugopal Iyer emrp->mrp_mask &= ~MRP_POOL;
83950dc2366fSVenugopal Iyer bzero(emrp->mrp_pool, MAXPATHLEN);
83960dc2366fSVenugopal Iyer }
83970dc2366fSVenugopal Iyer }
83980dc2366fSVenugopal Iyer
83990dc2366fSVenugopal Iyer struct mac_pool_arg {
84000dc2366fSVenugopal Iyer char mpa_poolname[MAXPATHLEN];
84010dc2366fSVenugopal Iyer pool_event_t mpa_what;
84020dc2366fSVenugopal Iyer };
84030dc2366fSVenugopal Iyer
84040dc2366fSVenugopal Iyer /*ARGSUSED*/
84050dc2366fSVenugopal Iyer static uint_t
mac_pool_link_update(mod_hash_key_t key,mod_hash_val_t * val,void * arg)84060dc2366fSVenugopal Iyer mac_pool_link_update(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
84070dc2366fSVenugopal Iyer {
84080dc2366fSVenugopal Iyer struct mac_pool_arg *mpa = arg;
84090dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)val;
84100dc2366fSVenugopal Iyer mac_client_impl_t *mcip;
84110dc2366fSVenugopal Iyer mac_resource_props_t *mrp, *emrp;
84120dc2366fSVenugopal Iyer boolean_t pool_update = B_FALSE;
84130dc2366fSVenugopal Iyer boolean_t pool_clear = B_FALSE;
84140dc2366fSVenugopal Iyer boolean_t use_default = B_FALSE;
84150dc2366fSVenugopal Iyer cpupart_t *cpupart = NULL;
84160dc2366fSVenugopal Iyer
84170dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
84180dc2366fSVenugopal Iyer i_mac_perim_enter(mip);
84190dc2366fSVenugopal Iyer for (mcip = mip->mi_clients_list; mcip != NULL;
84200dc2366fSVenugopal Iyer mcip = mcip->mci_client_next) {
84210dc2366fSVenugopal Iyer pool_update = B_FALSE;
84220dc2366fSVenugopal Iyer pool_clear = B_FALSE;
84230dc2366fSVenugopal Iyer use_default = B_FALSE;
84240dc2366fSVenugopal Iyer mac_client_get_resources((mac_client_handle_t)mcip, mrp);
84250dc2366fSVenugopal Iyer emrp = MCIP_EFFECTIVE_PROPS(mcip);
84260dc2366fSVenugopal Iyer
84270dc2366fSVenugopal Iyer /*
84280dc2366fSVenugopal Iyer * When pools are enabled
84290dc2366fSVenugopal Iyer */
84300dc2366fSVenugopal Iyer if ((mpa->mpa_what == POOL_E_ENABLE) &&
84310dc2366fSVenugopal Iyer ((mrp->mrp_mask & MRP_CPUS) == 0)) {
84320dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_POOL;
84330dc2366fSVenugopal Iyer pool_update = B_TRUE;
84340dc2366fSVenugopal Iyer }
84350dc2366fSVenugopal Iyer
84360dc2366fSVenugopal Iyer /*
84370dc2366fSVenugopal Iyer * When pools are disabled
84380dc2366fSVenugopal Iyer */
84390dc2366fSVenugopal Iyer if ((mpa->mpa_what == POOL_E_DISABLE) &&
84400dc2366fSVenugopal Iyer ((mrp->mrp_mask & MRP_CPUS) == 0)) {
84410dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_POOL;
84420dc2366fSVenugopal Iyer pool_clear = B_TRUE;
84430dc2366fSVenugopal Iyer }
84440dc2366fSVenugopal Iyer
84450dc2366fSVenugopal Iyer /*
84460dc2366fSVenugopal Iyer * Look for links with the pool property set and the poolname
84470dc2366fSVenugopal Iyer * matching the one which is changing.
84480dc2366fSVenugopal Iyer */
84490dc2366fSVenugopal Iyer if (strcmp(mrp->mrp_pool, mpa->mpa_poolname) == 0) {
84500dc2366fSVenugopal Iyer /*
84510dc2366fSVenugopal Iyer * The pool associated with the link has changed.
84520dc2366fSVenugopal Iyer */
84530dc2366fSVenugopal Iyer if (mpa->mpa_what == POOL_E_CHANGE) {
84540dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_POOL;
84550dc2366fSVenugopal Iyer pool_update = B_TRUE;
84560dc2366fSVenugopal Iyer }
84570dc2366fSVenugopal Iyer }
84580dc2366fSVenugopal Iyer
84590dc2366fSVenugopal Iyer /*
84600dc2366fSVenugopal Iyer * This link is associated with pool_default and
84610dc2366fSVenugopal Iyer * pool_default has changed.
84620dc2366fSVenugopal Iyer */
84630dc2366fSVenugopal Iyer if ((mpa->mpa_what == POOL_E_CHANGE) &&
84640dc2366fSVenugopal Iyer (strcmp(emrp->mrp_pool, "pool_default") == 0) &&
84650dc2366fSVenugopal Iyer (strcmp(mpa->mpa_poolname, "pool_default") == 0)) {
84660dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_POOL;
84670dc2366fSVenugopal Iyer pool_update = B_TRUE;
84680dc2366fSVenugopal Iyer }
84690dc2366fSVenugopal Iyer
84700dc2366fSVenugopal Iyer /*
84710dc2366fSVenugopal Iyer * Get new list of cpus for the pool, bind network
84720dc2366fSVenugopal Iyer * threads to new list of cpus and update resources.
84730dc2366fSVenugopal Iyer */
84740dc2366fSVenugopal Iyer if (pool_update) {
84750dc2366fSVenugopal Iyer if (MCIP_DATAPATH_SETUP(mcip)) {
84760dc2366fSVenugopal Iyer pool_lock();
84770dc2366fSVenugopal Iyer cpupart = mac_pset_find(mrp, &use_default);
84780dc2366fSVenugopal Iyer mac_fanout_setup(mcip, mcip->mci_flent, mrp,
84790dc2366fSVenugopal Iyer mac_rx_deliver, mcip, NULL, cpupart);
84800dc2366fSVenugopal Iyer mac_set_pool_effective(use_default, cpupart,
84810dc2366fSVenugopal Iyer mrp, emrp);
84820dc2366fSVenugopal Iyer pool_unlock();
84830dc2366fSVenugopal Iyer }
84840dc2366fSVenugopal Iyer mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip),
84850dc2366fSVenugopal Iyer B_FALSE);
84860dc2366fSVenugopal Iyer }
84870dc2366fSVenugopal Iyer
84880dc2366fSVenugopal Iyer /*
84890dc2366fSVenugopal Iyer * Clear the effective pool and bind network threads
84900dc2366fSVenugopal Iyer * to any available CPU.
84910dc2366fSVenugopal Iyer */
84920dc2366fSVenugopal Iyer if (pool_clear) {
84930dc2366fSVenugopal Iyer if (MCIP_DATAPATH_SETUP(mcip)) {
84940dc2366fSVenugopal Iyer emrp->mrp_mask &= ~MRP_POOL;
84950dc2366fSVenugopal Iyer bzero(emrp->mrp_pool, MAXPATHLEN);
84960dc2366fSVenugopal Iyer mac_fanout_setup(mcip, mcip->mci_flent, mrp,
84970dc2366fSVenugopal Iyer mac_rx_deliver, mcip, NULL, NULL);
84980dc2366fSVenugopal Iyer }
84990dc2366fSVenugopal Iyer mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip),
85000dc2366fSVenugopal Iyer B_FALSE);
85010dc2366fSVenugopal Iyer }
85020dc2366fSVenugopal Iyer }
85030dc2366fSVenugopal Iyer i_mac_perim_exit(mip);
85040dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp));
85050dc2366fSVenugopal Iyer return (MH_WALK_CONTINUE);
85060dc2366fSVenugopal Iyer }
85070dc2366fSVenugopal Iyer
85080dc2366fSVenugopal Iyer static void
mac_pool_update(void * arg)85090dc2366fSVenugopal Iyer mac_pool_update(void *arg)
85100dc2366fSVenugopal Iyer {
85110dc2366fSVenugopal Iyer mod_hash_walk(i_mac_impl_hash, mac_pool_link_update, arg);
85120dc2366fSVenugopal Iyer kmem_free(arg, sizeof (struct mac_pool_arg));
85130dc2366fSVenugopal Iyer }
85140dc2366fSVenugopal Iyer
85150dc2366fSVenugopal Iyer /*
85160dc2366fSVenugopal Iyer * Callback function to be executed when a noteworthy pool event
85170dc2366fSVenugopal Iyer * takes place.
85180dc2366fSVenugopal Iyer */
85190dc2366fSVenugopal Iyer /* ARGSUSED */
85200dc2366fSVenugopal Iyer static void
mac_pool_event_cb(pool_event_t what,poolid_t id,void * arg)85210dc2366fSVenugopal Iyer mac_pool_event_cb(pool_event_t what, poolid_t id, void *arg)
85220dc2366fSVenugopal Iyer {
85230dc2366fSVenugopal Iyer pool_t *pool;
85240dc2366fSVenugopal Iyer char *poolname = NULL;
85250dc2366fSVenugopal Iyer struct mac_pool_arg *mpa;
85260dc2366fSVenugopal Iyer
85270dc2366fSVenugopal Iyer pool_lock();
85280dc2366fSVenugopal Iyer mpa = kmem_zalloc(sizeof (struct mac_pool_arg), KM_SLEEP);
85290dc2366fSVenugopal Iyer
85300dc2366fSVenugopal Iyer switch (what) {
85310dc2366fSVenugopal Iyer case POOL_E_ENABLE:
85320dc2366fSVenugopal Iyer case POOL_E_DISABLE:
85330dc2366fSVenugopal Iyer break;
85340dc2366fSVenugopal Iyer
85350dc2366fSVenugopal Iyer case POOL_E_CHANGE:
85360dc2366fSVenugopal Iyer pool = pool_lookup_pool_by_id(id);
85370dc2366fSVenugopal Iyer if (pool == NULL) {
85380dc2366fSVenugopal Iyer kmem_free(mpa, sizeof (struct mac_pool_arg));
85390dc2366fSVenugopal Iyer pool_unlock();
85400dc2366fSVenugopal Iyer return;
85410dc2366fSVenugopal Iyer }
85420dc2366fSVenugopal Iyer pool_get_name(pool, &poolname);
85430dc2366fSVenugopal Iyer (void) strlcpy(mpa->mpa_poolname, poolname,
85440dc2366fSVenugopal Iyer sizeof (mpa->mpa_poolname));
85450dc2366fSVenugopal Iyer break;
85460dc2366fSVenugopal Iyer
85470dc2366fSVenugopal Iyer default:
85480dc2366fSVenugopal Iyer kmem_free(mpa, sizeof (struct mac_pool_arg));
85490dc2366fSVenugopal Iyer pool_unlock();
85500dc2366fSVenugopal Iyer return;
85510dc2366fSVenugopal Iyer }
85520dc2366fSVenugopal Iyer pool_unlock();
85530dc2366fSVenugopal Iyer
85540dc2366fSVenugopal Iyer mpa->mpa_what = what;
85550dc2366fSVenugopal Iyer
85560dc2366fSVenugopal Iyer mac_pool_update(mpa);
85570dc2366fSVenugopal Iyer }
85580dc2366fSVenugopal Iyer
85590dc2366fSVenugopal Iyer /*
85600dc2366fSVenugopal Iyer * Set effective rings property. This could be called from datapath_setup/
85610dc2366fSVenugopal Iyer * datapath_teardown or set-linkprop.
85620dc2366fSVenugopal Iyer * If the group is reserved we just go ahead and set the effective rings.
85630dc2366fSVenugopal Iyer * Additionally, for TX this could mean the default group has lost/gained
85640dc2366fSVenugopal Iyer * some rings, so if the default group is reserved, we need to adjust the
85650dc2366fSVenugopal Iyer * effective rings for the default group clients. For RX, if we are working
856684de666eSRyan Zezeski * with the non-default group, we just need to reset the effective props
85670dc2366fSVenugopal Iyer * for the default group clients.
85680dc2366fSVenugopal Iyer */
85690dc2366fSVenugopal Iyer void
mac_set_rings_effective(mac_client_impl_t * mcip)85700dc2366fSVenugopal Iyer mac_set_rings_effective(mac_client_impl_t *mcip)
85710dc2366fSVenugopal Iyer {
85720dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
85730dc2366fSVenugopal Iyer mac_group_t *grp;
85740dc2366fSVenugopal Iyer mac_group_t *defgrp;
85750dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent;
85760dc2366fSVenugopal Iyer mac_resource_props_t *emrp = MCIP_EFFECTIVE_PROPS(mcip);
85770dc2366fSVenugopal Iyer mac_grp_client_t *mgcp;
85780dc2366fSVenugopal Iyer mac_client_impl_t *gmcip;
85790dc2366fSVenugopal Iyer
85800dc2366fSVenugopal Iyer grp = flent->fe_rx_ring_group;
85810dc2366fSVenugopal Iyer if (grp != NULL) {
85820dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_RX_GROUP(mip);
85830dc2366fSVenugopal Iyer /*
85840dc2366fSVenugopal Iyer * If we have reserved a group, set the effective rings
85850dc2366fSVenugopal Iyer * to the ring count in the group.
85860dc2366fSVenugopal Iyer */
85870dc2366fSVenugopal Iyer if (grp->mrg_state == MAC_GROUP_STATE_RESERVED) {
85880dc2366fSVenugopal Iyer emrp->mrp_mask |= MRP_RX_RINGS;
85890dc2366fSVenugopal Iyer emrp->mrp_nrxrings = grp->mrg_cur_count;
85900dc2366fSVenugopal Iyer }
85910dc2366fSVenugopal Iyer
85920dc2366fSVenugopal Iyer /*
85930dc2366fSVenugopal Iyer * We go through the clients in the shared group and
85940dc2366fSVenugopal Iyer * reset the effective properties. It is possible this
85950dc2366fSVenugopal Iyer * might have already been done for some client (i.e.
85960dc2366fSVenugopal Iyer * if some client is being moved to a group that is
85970dc2366fSVenugopal Iyer * already shared). The case where the default group is
85980dc2366fSVenugopal Iyer * RESERVED is taken care of above (note in the RX side if
85990dc2366fSVenugopal Iyer * there is a non-default group, the default group is always
86000dc2366fSVenugopal Iyer * SHARED).
86010dc2366fSVenugopal Iyer */
86020dc2366fSVenugopal Iyer if (grp != defgrp || grp->mrg_state == MAC_GROUP_STATE_SHARED) {
86030dc2366fSVenugopal Iyer if (grp->mrg_state == MAC_GROUP_STATE_SHARED)
86040dc2366fSVenugopal Iyer mgcp = grp->mrg_clients;
86050dc2366fSVenugopal Iyer else
86060dc2366fSVenugopal Iyer mgcp = defgrp->mrg_clients;
86070dc2366fSVenugopal Iyer while (mgcp != NULL) {
86080dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
86090dc2366fSVenugopal Iyer emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86100dc2366fSVenugopal Iyer if (emrp->mrp_mask & MRP_RX_RINGS) {
86110dc2366fSVenugopal Iyer emrp->mrp_mask &= ~MRP_RX_RINGS;
86120dc2366fSVenugopal Iyer emrp->mrp_nrxrings = 0;
86130dc2366fSVenugopal Iyer }
86140dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
86150dc2366fSVenugopal Iyer }
86160dc2366fSVenugopal Iyer }
86170dc2366fSVenugopal Iyer }
86180dc2366fSVenugopal Iyer
86190dc2366fSVenugopal Iyer /* Now the TX side */
86200dc2366fSVenugopal Iyer grp = flent->fe_tx_ring_group;
86210dc2366fSVenugopal Iyer if (grp != NULL) {
86220dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip);
86230dc2366fSVenugopal Iyer
86240dc2366fSVenugopal Iyer if (grp->mrg_state == MAC_GROUP_STATE_RESERVED) {
86250dc2366fSVenugopal Iyer emrp->mrp_mask |= MRP_TX_RINGS;
86260dc2366fSVenugopal Iyer emrp->mrp_ntxrings = grp->mrg_cur_count;
86270dc2366fSVenugopal Iyer } else if (grp->mrg_state == MAC_GROUP_STATE_SHARED) {
86280dc2366fSVenugopal Iyer mgcp = grp->mrg_clients;
86290dc2366fSVenugopal Iyer while (mgcp != NULL) {
86300dc2366fSVenugopal Iyer gmcip = mgcp->mgc_client;
86310dc2366fSVenugopal Iyer emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86320dc2366fSVenugopal Iyer if (emrp->mrp_mask & MRP_TX_RINGS) {
86330dc2366fSVenugopal Iyer emrp->mrp_mask &= ~MRP_TX_RINGS;
86340dc2366fSVenugopal Iyer emrp->mrp_ntxrings = 0;
86350dc2366fSVenugopal Iyer }
86360dc2366fSVenugopal Iyer mgcp = mgcp->mgc_next;
86370dc2366fSVenugopal Iyer }
86380dc2366fSVenugopal Iyer }
86390dc2366fSVenugopal Iyer
86400dc2366fSVenugopal Iyer /*
86410dc2366fSVenugopal Iyer * If the group is not the default group and the default
86420dc2366fSVenugopal Iyer * group is reserved, the ring count in the default group
86430dc2366fSVenugopal Iyer * might have changed, update it.
86440dc2366fSVenugopal Iyer */
86450dc2366fSVenugopal Iyer if (grp != defgrp &&
86460dc2366fSVenugopal Iyer defgrp->mrg_state == MAC_GROUP_STATE_RESERVED) {
86470dc2366fSVenugopal Iyer gmcip = MAC_GROUP_ONLY_CLIENT(defgrp);
86480dc2366fSVenugopal Iyer emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86490dc2366fSVenugopal Iyer emrp->mrp_ntxrings = defgrp->mrg_cur_count;
86500dc2366fSVenugopal Iyer }
86510dc2366fSVenugopal Iyer }
86520dc2366fSVenugopal Iyer emrp = MCIP_EFFECTIVE_PROPS(mcip);
86530dc2366fSVenugopal Iyer }
86540dc2366fSVenugopal Iyer
86550dc2366fSVenugopal Iyer /*
86560dc2366fSVenugopal Iyer * Check if the primary is in the default group. If so, see if we
86570dc2366fSVenugopal Iyer * can give it a an exclusive group now that another client is
86580dc2366fSVenugopal Iyer * being configured. We take the primary out of the default group
86590dc2366fSVenugopal Iyer * because the multicast/broadcast packets for the all the clients
86600dc2366fSVenugopal Iyer * will land in the default ring in the default group which means
86610dc2366fSVenugopal Iyer * any client in the default group, even if it is the only on in
86620dc2366fSVenugopal Iyer * the group, will lose exclusive access to the rings, hence
86630dc2366fSVenugopal Iyer * polling.
86640dc2366fSVenugopal Iyer */
86650dc2366fSVenugopal Iyer mac_client_impl_t *
mac_check_primary_relocation(mac_client_impl_t * mcip,boolean_t rxhw)86660dc2366fSVenugopal Iyer mac_check_primary_relocation(mac_client_impl_t *mcip, boolean_t rxhw)
86670dc2366fSVenugopal Iyer {
86680dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip;
86690dc2366fSVenugopal Iyer mac_group_t *defgrp = MAC_DEFAULT_RX_GROUP(mip);
86700dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent;
86710dc2366fSVenugopal Iyer mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
86720dc2366fSVenugopal Iyer uint8_t *mac_addr;
86730dc2366fSVenugopal Iyer mac_group_t *ngrp;
86740dc2366fSVenugopal Iyer
86750dc2366fSVenugopal Iyer /*
86760dc2366fSVenugopal Iyer * Check if the primary is in the default group, if not
86770dc2366fSVenugopal Iyer * or if it is explicitly configured to be in the default
86780dc2366fSVenugopal Iyer * group OR set the RX rings property, return.
86790dc2366fSVenugopal Iyer */
86800dc2366fSVenugopal Iyer if (flent->fe_rx_ring_group != defgrp || mrp->mrp_mask & MRP_RX_RINGS)
86810dc2366fSVenugopal Iyer return (NULL);
86820dc2366fSVenugopal Iyer
86830dc2366fSVenugopal Iyer /*
86840dc2366fSVenugopal Iyer * If the new client needs an exclusive group and we
86850dc2366fSVenugopal Iyer * don't have another for the primary, return.
86860dc2366fSVenugopal Iyer */
86870dc2366fSVenugopal Iyer if (rxhw && mip->mi_rxhwclnt_avail < 2)
86880dc2366fSVenugopal Iyer return (NULL);
86890dc2366fSVenugopal Iyer
86900dc2366fSVenugopal Iyer mac_addr = flent->fe_flow_desc.fd_dst_mac;
86910dc2366fSVenugopal Iyer /*
86920dc2366fSVenugopal Iyer * We call this when we are setting up the datapath for
86930dc2366fSVenugopal Iyer * the first non-primary.
86940dc2366fSVenugopal Iyer */
86950dc2366fSVenugopal Iyer ASSERT(mip->mi_nactiveclients == 2);
869684de666eSRyan Zezeski
86970dc2366fSVenugopal Iyer /*
86980dc2366fSVenugopal Iyer * OK, now we have the primary that needs to be relocated.
86990dc2366fSVenugopal Iyer */
87000dc2366fSVenugopal Iyer ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
87010dc2366fSVenugopal Iyer if (ngrp == NULL)
87020dc2366fSVenugopal Iyer return (NULL);
87030dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) {
87040dc2366fSVenugopal Iyer mac_stop_group(ngrp);
87050dc2366fSVenugopal Iyer return (NULL);
87060dc2366fSVenugopal Iyer }
87070dc2366fSVenugopal Iyer return (mcip);
87080dc2366fSVenugopal Iyer }
870945d3dd98SRobert Mustacchi
871045d3dd98SRobert Mustacchi void
mac_transceiver_init(mac_impl_t * mip)871145d3dd98SRobert Mustacchi mac_transceiver_init(mac_impl_t *mip)
871245d3dd98SRobert Mustacchi {
871345d3dd98SRobert Mustacchi if (mac_capab_get((mac_handle_t)mip, MAC_CAPAB_TRANSCEIVER,
871445d3dd98SRobert Mustacchi &mip->mi_transceiver)) {
871545d3dd98SRobert Mustacchi /*
871645d3dd98SRobert Mustacchi * The driver set a flag that we don't know about. In this case,
871745d3dd98SRobert Mustacchi * we need to warn about that case and ignore this capability.
871845d3dd98SRobert Mustacchi */
871945d3dd98SRobert Mustacchi if (mip->mi_transceiver.mct_flags != 0) {
872045d3dd98SRobert Mustacchi dev_err(mip->mi_dip, CE_WARN, "driver set transceiver "
872145d3dd98SRobert Mustacchi "flags to invalid value: 0x%x, ignoring "
872245d3dd98SRobert Mustacchi "capability", mip->mi_transceiver.mct_flags);
872345d3dd98SRobert Mustacchi bzero(&mip->mi_transceiver,
872445d3dd98SRobert Mustacchi sizeof (mac_capab_transceiver_t));
872545d3dd98SRobert Mustacchi }
872645d3dd98SRobert Mustacchi } else {
872745d3dd98SRobert Mustacchi bzero(&mip->mi_transceiver,
872845d3dd98SRobert Mustacchi sizeof (mac_capab_transceiver_t));
872945d3dd98SRobert Mustacchi }
873045d3dd98SRobert Mustacchi }
873145d3dd98SRobert Mustacchi
873245d3dd98SRobert Mustacchi int
mac_transceiver_count(mac_handle_t mh,uint_t * countp)873345d3dd98SRobert Mustacchi mac_transceiver_count(mac_handle_t mh, uint_t *countp)
873445d3dd98SRobert Mustacchi {
873545d3dd98SRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
873645d3dd98SRobert Mustacchi
873745d3dd98SRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
873845d3dd98SRobert Mustacchi
873945d3dd98SRobert Mustacchi if (mip->mi_transceiver.mct_ntransceivers == 0)
874045d3dd98SRobert Mustacchi return (ENOTSUP);
874145d3dd98SRobert Mustacchi
874245d3dd98SRobert Mustacchi *countp = mip->mi_transceiver.mct_ntransceivers;
874345d3dd98SRobert Mustacchi return (0);
874445d3dd98SRobert Mustacchi }
874545d3dd98SRobert Mustacchi
874645d3dd98SRobert Mustacchi int
mac_transceiver_info(mac_handle_t mh,uint_t tranid,boolean_t * present,boolean_t * usable)874745d3dd98SRobert Mustacchi mac_transceiver_info(mac_handle_t mh, uint_t tranid, boolean_t *present,
874845d3dd98SRobert Mustacchi boolean_t *usable)
874945d3dd98SRobert Mustacchi {
875045d3dd98SRobert Mustacchi int ret;
875145d3dd98SRobert Mustacchi mac_transceiver_info_t info;
875245d3dd98SRobert Mustacchi
875345d3dd98SRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
875445d3dd98SRobert Mustacchi
875545d3dd98SRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
875645d3dd98SRobert Mustacchi
875745d3dd98SRobert Mustacchi if (mip->mi_transceiver.mct_info == NULL ||
875845d3dd98SRobert Mustacchi mip->mi_transceiver.mct_ntransceivers == 0)
875945d3dd98SRobert Mustacchi return (ENOTSUP);
876045d3dd98SRobert Mustacchi
876145d3dd98SRobert Mustacchi if (tranid >= mip->mi_transceiver.mct_ntransceivers)
876245d3dd98SRobert Mustacchi return (EINVAL);
876345d3dd98SRobert Mustacchi
876445d3dd98SRobert Mustacchi bzero(&info, sizeof (mac_transceiver_info_t));
876545d3dd98SRobert Mustacchi if ((ret = mip->mi_transceiver.mct_info(mip->mi_driver, tranid,
876645d3dd98SRobert Mustacchi &info)) != 0) {
876745d3dd98SRobert Mustacchi return (ret);
876845d3dd98SRobert Mustacchi }
876945d3dd98SRobert Mustacchi
877045d3dd98SRobert Mustacchi *present = info.mti_present;
877145d3dd98SRobert Mustacchi *usable = info.mti_usable;
877245d3dd98SRobert Mustacchi return (0);
877345d3dd98SRobert Mustacchi }
877445d3dd98SRobert Mustacchi
877545d3dd98SRobert Mustacchi int
mac_transceiver_read(mac_handle_t mh,uint_t tranid,uint_t page,void * buf,size_t nbytes,off_t offset,size_t * nread)877645d3dd98SRobert Mustacchi mac_transceiver_read(mac_handle_t mh, uint_t tranid, uint_t page, void *buf,
877745d3dd98SRobert Mustacchi size_t nbytes, off_t offset, size_t *nread)
877845d3dd98SRobert Mustacchi {
877945d3dd98SRobert Mustacchi int ret;
878045d3dd98SRobert Mustacchi size_t nr;
878145d3dd98SRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
878245d3dd98SRobert Mustacchi
878345d3dd98SRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
878445d3dd98SRobert Mustacchi
878545d3dd98SRobert Mustacchi if (mip->mi_transceiver.mct_read == NULL)
878645d3dd98SRobert Mustacchi return (ENOTSUP);
878745d3dd98SRobert Mustacchi
878845d3dd98SRobert Mustacchi if (tranid >= mip->mi_transceiver.mct_ntransceivers)
878945d3dd98SRobert Mustacchi return (EINVAL);
879045d3dd98SRobert Mustacchi
879145d3dd98SRobert Mustacchi /*
879245d3dd98SRobert Mustacchi * All supported pages today are 256 bytes wide. Make sure offset +
879345d3dd98SRobert Mustacchi * nbytes never exceeds that.
879445d3dd98SRobert Mustacchi */
879545d3dd98SRobert Mustacchi if (offset < 0 || offset >= 256 || nbytes > 256 ||
879645d3dd98SRobert Mustacchi offset + nbytes > 256)
879745d3dd98SRobert Mustacchi return (EINVAL);
879845d3dd98SRobert Mustacchi
879945d3dd98SRobert Mustacchi if (nread == NULL)
880045d3dd98SRobert Mustacchi nread = &nr;
880145d3dd98SRobert Mustacchi ret = mip->mi_transceiver.mct_read(mip->mi_driver, tranid, page, buf,
880245d3dd98SRobert Mustacchi nbytes, offset, nread);
880345d3dd98SRobert Mustacchi if (ret == 0 && *nread > nbytes) {
880445d3dd98SRobert Mustacchi dev_err(mip->mi_dip, CE_PANIC, "driver wrote %lu bytes into "
880545d3dd98SRobert Mustacchi "%lu byte sized buffer, possible memory corruption",
880645d3dd98SRobert Mustacchi *nread, nbytes);
880745d3dd98SRobert Mustacchi }
880845d3dd98SRobert Mustacchi
880945d3dd98SRobert Mustacchi return (ret);
881045d3dd98SRobert Mustacchi }
8811c1e9c696SRobert Mustacchi
8812c1e9c696SRobert Mustacchi void
mac_led_init(mac_impl_t * mip)8813c1e9c696SRobert Mustacchi mac_led_init(mac_impl_t *mip)
8814c1e9c696SRobert Mustacchi {
8815c1e9c696SRobert Mustacchi mip->mi_led_modes = MAC_LED_DEFAULT;
8816c1e9c696SRobert Mustacchi
8817c1e9c696SRobert Mustacchi if (!mac_capab_get((mac_handle_t)mip, MAC_CAPAB_LED, &mip->mi_led)) {
8818c1e9c696SRobert Mustacchi bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8819c1e9c696SRobert Mustacchi return;
8820c1e9c696SRobert Mustacchi }
8821c1e9c696SRobert Mustacchi
8822c1e9c696SRobert Mustacchi if (mip->mi_led.mcl_flags != 0) {
8823c1e9c696SRobert Mustacchi dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
8824c1e9c696SRobert Mustacchi "flags to invalid value: 0x%x, ignoring "
8825c1e9c696SRobert Mustacchi "capability", mip->mi_transceiver.mct_flags);
8826c1e9c696SRobert Mustacchi bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8827c1e9c696SRobert Mustacchi return;
8828c1e9c696SRobert Mustacchi }
8829c1e9c696SRobert Mustacchi
8830c1e9c696SRobert Mustacchi if ((mip->mi_led.mcl_modes & ~MAC_LED_ALL) != 0) {
8831c1e9c696SRobert Mustacchi dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
8832c1e9c696SRobert Mustacchi "supported modes to invalid value: 0x%x, ignoring "
8833c1e9c696SRobert Mustacchi "capability", mip->mi_transceiver.mct_flags);
8834c1e9c696SRobert Mustacchi bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8835c1e9c696SRobert Mustacchi return;
8836c1e9c696SRobert Mustacchi }
8837c1e9c696SRobert Mustacchi }
8838c1e9c696SRobert Mustacchi
8839c1e9c696SRobert Mustacchi int
mac_led_get(mac_handle_t mh,mac_led_mode_t * supported,mac_led_mode_t * active)8840c1e9c696SRobert Mustacchi mac_led_get(mac_handle_t mh, mac_led_mode_t *supported, mac_led_mode_t *active)
8841c1e9c696SRobert Mustacchi {
8842c1e9c696SRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
8843c1e9c696SRobert Mustacchi
8844c1e9c696SRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
8845c1e9c696SRobert Mustacchi
8846c1e9c696SRobert Mustacchi if (mip->mi_led.mcl_set == NULL)
8847c1e9c696SRobert Mustacchi return (ENOTSUP);
8848c1e9c696SRobert Mustacchi
8849c1e9c696SRobert Mustacchi *supported = mip->mi_led.mcl_modes;
8850c1e9c696SRobert Mustacchi *active = mip->mi_led_modes;
8851c1e9c696SRobert Mustacchi
8852c1e9c696SRobert Mustacchi return (0);
8853c1e9c696SRobert Mustacchi }
8854c1e9c696SRobert Mustacchi
8855c1e9c696SRobert Mustacchi /*
8856c1e9c696SRobert Mustacchi * Update and multiplex the various LED requests. We only ever send one LED to
8857c1e9c696SRobert Mustacchi * the underlying driver at a time. As such, we end up multiplexing all
8858c1e9c696SRobert Mustacchi * requested states and picking one to send down to the driver.
8859c1e9c696SRobert Mustacchi */
8860c1e9c696SRobert Mustacchi int
mac_led_set(mac_handle_t mh,mac_led_mode_t desired)8861c1e9c696SRobert Mustacchi mac_led_set(mac_handle_t mh, mac_led_mode_t desired)
8862c1e9c696SRobert Mustacchi {
8863c1e9c696SRobert Mustacchi int ret;
8864c1e9c696SRobert Mustacchi mac_led_mode_t driver;
8865c1e9c696SRobert Mustacchi
8866c1e9c696SRobert Mustacchi mac_impl_t *mip = (mac_impl_t *)mh;
8867c1e9c696SRobert Mustacchi
8868c1e9c696SRobert Mustacchi ASSERT(MAC_PERIM_HELD(mh));
8869c1e9c696SRobert Mustacchi
8870c1e9c696SRobert Mustacchi /*
8871c1e9c696SRobert Mustacchi * If we've been passed a desired value of zero, that indicates that
8872c1e9c696SRobert Mustacchi * we're basically resetting to the value of zero, which is our default
8873c1e9c696SRobert Mustacchi * value.
8874c1e9c696SRobert Mustacchi */
8875c1e9c696SRobert Mustacchi if (desired == 0)
8876c1e9c696SRobert Mustacchi desired = MAC_LED_DEFAULT;
8877c1e9c696SRobert Mustacchi
8878c1e9c696SRobert Mustacchi if (mip->mi_led.mcl_set == NULL)
8879c1e9c696SRobert Mustacchi return (ENOTSUP);
8880c1e9c696SRobert Mustacchi
8881c1e9c696SRobert Mustacchi /*
8882c1e9c696SRobert Mustacchi * Catch both values that we don't know about and those that the driver
8883c1e9c696SRobert Mustacchi * doesn't support.
8884c1e9c696SRobert Mustacchi */
8885c1e9c696SRobert Mustacchi if ((desired & ~MAC_LED_ALL) != 0)
8886c1e9c696SRobert Mustacchi return (EINVAL);
8887c1e9c696SRobert Mustacchi
8888c1e9c696SRobert Mustacchi if ((desired & ~mip->mi_led.mcl_modes) != 0)
8889c1e9c696SRobert Mustacchi return (ENOTSUP);
8890c1e9c696SRobert Mustacchi
8891c1e9c696SRobert Mustacchi /*
8892c1e9c696SRobert Mustacchi * If we have the same value, then there is nothing to do.
8893c1e9c696SRobert Mustacchi */
8894c1e9c696SRobert Mustacchi if (desired == mip->mi_led_modes)
8895c1e9c696SRobert Mustacchi return (0);
8896c1e9c696SRobert Mustacchi
8897c1e9c696SRobert Mustacchi /*
8898c1e9c696SRobert Mustacchi * Based on the desired value, determine what to send to the driver. We
8899c1e9c696SRobert Mustacchi * only will send a single bit to the driver at any given time. IDENT
8900c1e9c696SRobert Mustacchi * takes priority over OFF or ON. We also let OFF take priority over the
8901c1e9c696SRobert Mustacchi * rest.
8902c1e9c696SRobert Mustacchi */
8903c1e9c696SRobert Mustacchi if (desired & MAC_LED_IDENT) {
8904c1e9c696SRobert Mustacchi driver = MAC_LED_IDENT;
8905c1e9c696SRobert Mustacchi } else if (desired & MAC_LED_OFF) {
8906c1e9c696SRobert Mustacchi driver = MAC_LED_OFF;
8907c1e9c696SRobert Mustacchi } else if (desired & MAC_LED_ON) {
8908c1e9c696SRobert Mustacchi driver = MAC_LED_ON;
8909c1e9c696SRobert Mustacchi } else {
8910c1e9c696SRobert Mustacchi driver = MAC_LED_DEFAULT;
8911c1e9c696SRobert Mustacchi }
8912c1e9c696SRobert Mustacchi
8913c1e9c696SRobert Mustacchi if ((ret = mip->mi_led.mcl_set(mip->mi_driver, driver, 0)) == 0) {
8914c1e9c696SRobert Mustacchi mip->mi_led_modes = desired;
8915c1e9c696SRobert Mustacchi }
8916c1e9c696SRobert Mustacchi
8917c1e9c696SRobert Mustacchi return (ret);
8918c1e9c696SRobert Mustacchi }
8919c61a1653SRyan Zezeski
8920c61a1653SRyan Zezeski /*
8921c61a1653SRyan Zezeski * Send packets through the Tx ring ('mrh') or through the default
8922c61a1653SRyan Zezeski * handler if no ring is specified. Before passing the packet down to
8923c61a1653SRyan Zezeski * the MAC provider, emulate any hardware offloads which have been
8924c61a1653SRyan Zezeski * requested but are not supported by the provider.
8925c61a1653SRyan Zezeski */
8926c61a1653SRyan Zezeski mblk_t *
mac_ring_tx(mac_handle_t mh,mac_ring_handle_t mrh,mblk_t * mp)8927c61a1653SRyan Zezeski mac_ring_tx(mac_handle_t mh, mac_ring_handle_t mrh, mblk_t *mp)
8928c61a1653SRyan Zezeski {
8929c61a1653SRyan Zezeski mac_impl_t *mip = (mac_impl_t *)mh;
8930c61a1653SRyan Zezeski
8931c61a1653SRyan Zezeski if (mrh == NULL)
8932c61a1653SRyan Zezeski mrh = mip->mi_default_tx_ring;
8933c61a1653SRyan Zezeski
8934c61a1653SRyan Zezeski if (mrh == NULL)
8935c61a1653SRyan Zezeski return (mip->mi_tx(mip->mi_driver, mp));
8936c61a1653SRyan Zezeski else
8937c61a1653SRyan Zezeski return (mac_hwring_tx(mrh, mp));
8938c61a1653SRyan Zezeski }
8939c61a1653SRyan Zezeski
8940c61a1653SRyan Zezeski /*
8941c61a1653SRyan Zezeski * This is the final stop before reaching the underlying MAC provider.
8942c61a1653SRyan Zezeski * This is also where the bridging hook is inserted. Packets that are
8943c61a1653SRyan Zezeski * bridged will return through mac_bridge_tx(), with rh nulled out if
8944c61a1653SRyan Zezeski * the bridge chooses to send output on a different link due to
8945c61a1653SRyan Zezeski * forwarding.
8946c61a1653SRyan Zezeski */
8947c61a1653SRyan Zezeski mblk_t *
mac_provider_tx(mac_impl_t * mip,mac_ring_handle_t rh,mblk_t * mp,mac_client_impl_t * mcip)8948c61a1653SRyan Zezeski mac_provider_tx(mac_impl_t *mip, mac_ring_handle_t rh, mblk_t *mp,
8949c61a1653SRyan Zezeski mac_client_impl_t *mcip)
8950c61a1653SRyan Zezeski {
8951c61a1653SRyan Zezeski /*
8952c61a1653SRyan Zezeski * If there is a bound Hybrid I/O share, send packets through
8953c61a1653SRyan Zezeski * the default tx ring. When there's a bound Hybrid I/O share,
8954c61a1653SRyan Zezeski * the tx rings of this client are mapped in the guest domain
8955c61a1653SRyan Zezeski * and not accessible from here.
8956c61a1653SRyan Zezeski */
8957c61a1653SRyan Zezeski if (mcip->mci_state_flags & MCIS_SHARE_BOUND)
8958c61a1653SRyan Zezeski rh = mip->mi_default_tx_ring;
8959c61a1653SRyan Zezeski
8960c61a1653SRyan Zezeski if (mip->mi_promisc_list != NULL)
8961c61a1653SRyan Zezeski mac_promisc_dispatch(mip, mp, mcip, B_FALSE);
8962c61a1653SRyan Zezeski
8963c61a1653SRyan Zezeski if (mip->mi_bridge_link == NULL)
8964c61a1653SRyan Zezeski return (mac_ring_tx((mac_handle_t)mip, rh, mp));
8965c61a1653SRyan Zezeski else
8966c61a1653SRyan Zezeski return (mac_bridge_tx(mip, rh, mp));
8967c61a1653SRyan Zezeski }
8968