dls_soft_ring.c revision 4d876314150ff07a7d5163d5e2f78785c8efeacb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* General Soft rings - Simulating Rx rings in S/W.
*
* This is a general purpose high-performance soft ring mechanism. It is
* similar to a taskq with a single worker thread. The dls creates a
* set of these rings to simulate the H/W Rx ring (DMA channels) some
* NICs have. The purpose is to present a common interface to IP
* so the individual squeues can control these rings and switch them
* between polling and interrupt mode.
*
* This code also serves as a fanout mechanism for fast NIC feeding slow
* CPU where incoming traffic can be separated into multiple soft rings
* based on capability negotiation with IP and IP also creates thread
* affinity to soft ring worker threads to CPU so that conenction to
*
* The soft rings can also be driven by a classifier which can direct
* traffic to individual soft rings based on the input from IP.
*/
#include <sys/condvar_impl.h>
#include <sys/dls_impl.h>
#include <sys/dls_soft_ring.h>
static void soft_ring_fire(void *);
static void soft_ring_worker(soft_ring_t *);
static void soft_ring_stop_workers(soft_ring_t **, int);
int soft_ring_workerwait_ms = 10;
/* The values above converted to ticks */
static int soft_ring_workerwait_tick = 0;
#define SOFT_RING_WORKER_WAKEUP(ringp) { \
\
/* \
* Queue isn't being processed, so take \
* any post enqueue actions needed before leaving. \
*/ \
if (tid != 0) { \
/* \
* Waiting for an enter() to process mblk(s). \
*/ \
\
/* \
* Times up and have a worker thread \
* waiting for work, so schedule it. \
*/ \
(ringp)->s_ring_tid = 0; \
} else { \
} \
} else if ((ringp)->s_ring_wait != 0) { \
(ringp)->s_ring_wait); \
} else { \
/* \
* Schedule the worker thread. \
*/ \
} \
}
/* \
* Enqueue our mblk chain. \
*/ \
\
else \
}
void
soft_ring_init(void)
{
}
/* ARGSUSED */
{
return (NULL);
if (bind != S_RING_BIND_NONE)
return (ringp);
}
soft_ring_t **
{
int i;
if ((ringp_list =
KM_NOSLEEP)) != NULL) {
for (i = 0; i < cnt; i++) {
if (ringp_list[i] == NULL)
break;
}
if (i != cnt) {
ringp_list = NULL;
}
}
return (ringp_list);
}
static void
{
int i;
for (i = 0; i < cnt; i++) {
soft_ring_unbind((void *)ringp);
ringp->s_ring_tid = 0;
/* Wake the worker so it can exit */
}
/*
* Here comes the tricky part. IP and driver ensure
* that packet flow has stopped but worker thread
* might still be draining the soft ring. We have
* already set the S_RING_DESTROY flag. We wait till
* the worker thread takes notice and stops processing
* the soft_ring and exits. It sets S_RING_DEAD on
* exiting.
*/
if (t_did)
}
}
void
{
int i;
for (i = 0; i < cnt; i++) {
}
/*
* when we are destroying the soft rings otherwise bad
* things will happen.
*/
}
}
/* ARGSUSED */
void
{
return;
}
if (cpu_is_online(cp)) {
}
}
void
soft_ring_unbind(void *arg)
{
return;
}
}
/*
* soft_ring_enter() - enter soft_ring sqp with mblk mp (which can be
* a chain), while tail points to the end and cnt in number of
* mblks in the chain.
*
* For a chain of single packet (i.e. mp == tail), go through the
* fast path if no one is processing the soft_ring and nothing is queued.
*
* The proc and arg for each mblk is already stored in the mblk in
* appropriate places.
*/
/* ARGSUSED */
void
{
int cnt = 1;
cnt++;
}
/*
* See if anything is already queued. If we are the
* first packet, do inline processing else queue the
* packet and do the drain.
*/
/*
* Fast-path, ok to process and nothing queued.
*/
/*
* We are the chain of 1 packet so
* go through this fast path.
*/
/*
* We processed inline our packet and
* nothing new has arrived. We are done.
*/
return;
}
} else {
}
/*
* We are here because either we couldn't do inline
* processing (because something was already queued),
* or we had a chanin of more than one packet,
* or something else arrived after we were done with
* inline processing.
*/
return;
} else {
/*
* Queue is already being processed. Just enqueue
* the packet and go away.
*/
} else
} else {
}
return;
}
}
/*
* PRIVATE FUNCTIONS
*/
static void
soft_ring_fire(void *arg)
{
if (ringp->s_ring_tid == 0) {
return;
}
ringp->s_ring_tid = 0;
}
}
/* ARGSUSED */
static void
{
ringp->s_ring_tid = 0;
ringp->s_ring_count = 0;
if (tid != 0) {
tid = 0;
}
}
}
static void
{
for (;;) {
goto destroy;
thread_exit();
}
}
goto still_wait;
}
}
}
}
void
{
if (type == SOFT_RING_NONE)
else
}
{
return (ret);
}
void
{
}
{
int i;
char name[64];
}
dip->di_soft_ring_size = 0;
return (B_FALSE);
}
for (i = 0; i < soft_ringp->dls_ring_cnt; i++) {
softring = softring_set[i];
(void *)soft_ringp->dls_rx_handle;
(mac_resource_t *)&mrf);
}
/*
* Note that soft_ring is enabled. This prevents further DLIOCHDRINFO
* ioctls from overwriting the receive function pointer.
*/
return (B_TRUE);
}
/* ARGSUSED */
void
{
int indx;
int key;
int hdr_len;
switch (dip->di_soft_ring_fanout_type) {
case SOFT_RING_SRC_HASH:
/*
* We get a chain of packets from the same remote. Make
* sure the same remote goes to same ring.
*/
mp_chain, 0);
break;
case SOFT_RING_RND_ROBIN:
case SOFT_RING_RANDOM:
/*
* Just send it to any possible soft ring
*/
break;
}
}