Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/netmap/netmap_freebsd.c
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/socket.h> /* sockaddrs */ | #include <sys/socket.h> /* sockaddrs */ | ||||
#include <sys/selinfo.h> | #include <sys/selinfo.h> | ||||
#include <sys/kthread.h> /* kthread_add() */ | #include <sys/kthread.h> /* kthread_add() */ | ||||
#include <sys/proc.h> /* PROC_LOCK() */ | #include <sys/proc.h> /* PROC_LOCK() */ | ||||
#include <sys/unistd.h> /* RFNOWAIT */ | #include <sys/unistd.h> /* RFNOWAIT */ | ||||
#include <sys/sched.h> /* sched_bind() */ | #include <sys/sched.h> /* sched_bind() */ | ||||
#include <sys/smp.h> /* mp_maxid */ | #include <sys/smp.h> /* mp_maxid */ | ||||
#include <sys/taskqueue.h> /* taskqueue_enqueue(), taskqueue_create(), ... */ | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_types.h> /* IFT_ETHER */ | #include <net/if_types.h> /* IFT_ETHER */ | ||||
#include <net/ethernet.h> /* ether_ifdetach */ | #include <net/ethernet.h> /* ether_ifdetach */ | ||||
#include <net/if_dl.h> /* LLADDR */ | #include <net/if_dl.h> /* LLADDR */ | ||||
#include <machine/bus.h> /* bus_dmamap_* */ | #include <machine/bus.h> /* bus_dmamap_* */ | ||||
#include <netinet/in.h> /* in6_cksum_pseudo() */ | #include <netinet/in.h> /* in6_cksum_pseudo() */ | ||||
#include <machine/in_cksum.h> /* in_pseudo(), in_cksum_hdr() */ | #include <machine/in_cksum.h> /* in_pseudo(), in_cksum_hdr() */ | ||||
#include <net/netmap.h> | #include <net/netmap.h> | ||||
#include <dev/netmap/netmap_kern.h> | #include <dev/netmap/netmap_kern.h> | ||||
#include <net/netmap_virt.h> | #include <net/netmap_virt.h> | ||||
#include <dev/netmap/netmap_mem2.h> | #include <dev/netmap/netmap_mem2.h> | ||||
/* ======================== FREEBSD-SPECIFIC ROUTINES ================== */ | /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */ | ||||
void nm_os_selinfo_init(NM_SELINFO_T *si) { | static void | ||||
struct mtx *m = &si->m; | nm_kqueue_notify(void *opaque, int pending) | ||||
mtx_init(m, "nm_kn_lock", NULL, MTX_DEF); | { | ||||
knlist_init_mtx(&si->si.si_note, m); | struct nm_selinfo *si = opaque; | ||||
/* We use a non-zero hint to distinguish this notification call | |||||
* from the call done in kqueue_scan(), which uses hint=0. | |||||
*/ | |||||
KNOTE_UNLOCKED(&si->si.si_note, /*hint=*/0x100); | |||||
} | } | ||||
int nm_os_selinfo_init(NM_SELINFO_T *si, const char *name) { | |||||
int err; | |||||
TASK_INIT(&si->ntfytask, 0, nm_kqueue_notify, si); | |||||
si->ntfytq = taskqueue_create(name, M_NOWAIT, | |||||
taskqueue_thread_enqueue, &si->ntfytq); | |||||
if (si->ntfytq == NULL) | |||||
return -ENOMEM; | |||||
err = taskqueue_start_threads(&si->ntfytq, 1, PI_NET, "tq %s", name); | |||||
if (err) { | |||||
taskqueue_free(si->ntfytq); | |||||
si->ntfytq = NULL; | |||||
return err; | |||||
} | |||||
snprintf(si->mtxname, sizeof(si->mtxname), "nmkl%s", name); | |||||
mtx_init(&si->m, si->mtxname, NULL, MTX_DEF); | |||||
knlist_init_mtx(&si->si.si_note, &si->m); | |||||
return (0); | |||||
} | |||||
void | void | ||||
nm_os_selinfo_uninit(NM_SELINFO_T *si) | nm_os_selinfo_uninit(NM_SELINFO_T *si) | ||||
{ | { | ||||
/* XXX kqueue(9) needed; these will mirror knlist_init. */ | if (si->ntfytq == NULL) { | ||||
return; /* si was not initialized */ | |||||
} | |||||
taskqueue_drain(si->ntfytq, &si->ntfytask); | |||||
taskqueue_free(si->ntfytq); | |||||
si->ntfytq = NULL; | |||||
knlist_delete(&si->si.si_note, curthread, /*islocked=*/0); | knlist_delete(&si->si.si_note, curthread, /*islocked=*/0); | ||||
knlist_destroy(&si->si.si_note); | knlist_destroy(&si->si.si_note); | ||||
/* now we don't need the mutex anymore */ | /* now we don't need the mutex anymore */ | ||||
mtx_destroy(&si->m); | mtx_destroy(&si->m); | ||||
} | } | ||||
void * | void * | ||||
nm_os_malloc(size_t size) | nm_os_malloc(size_t size) | ||||
▲ Show 20 Lines • Show All 1,191 Lines • ▼ Show 20 Lines | nm_os_kctx_destroy(struct nm_kctx *nmk) | ||||
free(nmk, M_DEVBUF); | free(nmk, M_DEVBUF); | ||||
} | } | ||||
/******************** kqueue support ****************/ | /******************** kqueue support ****************/ | ||||
/* | /* | ||||
* In addition to calling selwakeuppri(), nm_os_selwakeup() also | * In addition to calling selwakeuppri(), nm_os_selwakeup() also | ||||
* needs to call KNOTE to wake up kqueue listeners. | * needs to call knote() to wake up kqueue listeners. | ||||
* We use a non-zero 'hint' argument to inform the netmap_knrw() | * This operation is deferred to a taskqueue in order to avoid possible | ||||
* function that it is being called from 'nm_os_selwakeup'; this | * lock order reversals; these may happen because knote() grabs a | ||||
* is necessary because when netmap_knrw() is called by the kevent | * private lock associated to the 'si' (see struct selinfo, | ||||
* subsystem (i.e. kevent_scan()) we also need to call netmap_poll(). | * struct nm_selinfo, and nm_os_selinfo_init), and nm_os_selwakeup() | ||||
* The knote uses a private mutex associated to the 'si' (see struct | * can be called while holding the lock associated to a different | ||||
* selinfo, struct nm_selinfo, and nm_os_selinfo_init). | * 'si'. | ||||
* When calling knote() we use a non-zero 'hint' argument to inform | |||||
* the netmap_knrw() function that it is being called from | |||||
* 'nm_os_selwakeup'; this is necessary because when netmap_knrw() is | |||||
* called by the kevent subsystem (i.e. kevent_scan()) we also need to | |||||
* call netmap_poll(). | |||||
* | * | ||||
* The netmap_kqfilter() function registers one or another f_event | * The netmap_kqfilter() function registers one or another f_event | ||||
* depending on read or write mode. A pointer to the struct | * depending on read or write mode. A pointer to the struct | ||||
* 'netmap_priv_d' is stored into kn->kn_hook, so that it can later | * 'netmap_priv_d' is stored into kn->kn_hook, so that it can later | ||||
* be passed to netmap_poll(). We pass NULL as a third argument to | * be passed to netmap_poll(). We pass NULL as a third argument to | ||||
* netmap_poll(), so that the latter only runs the txsync/rxsync | * netmap_poll(), so that the latter only runs the txsync/rxsync | ||||
* (if necessary), and skips the nm_os_selrecord() calls. | * (if necessary), and skips the nm_os_selrecord() calls. | ||||
*/ | */ | ||||
void | void | ||||
nm_os_selwakeup(struct nm_selinfo *si) | nm_os_selwakeup(struct nm_selinfo *si) | ||||
{ | { | ||||
if (netmap_verbose) | if (netmap_verbose) | ||||
nm_prinf("on knote %p", &si->si.si_note); | nm_prinf("on knote %p", &si->si.si_note); | ||||
selwakeuppri(&si->si, PI_NET); | selwakeuppri(&si->si, PI_NET); | ||||
/* We use a non-zero hint to distinguish this notification call | taskqueue_enqueue(si->ntfytq, &si->ntfytask); | ||||
* from the call done in kqueue_scan(), which uses hint=0. | |||||
*/ | |||||
KNOTE(&si->si.si_note, /*hint=*/0x100, | |||||
mtx_owned(&si->m) ? KNF_LISTLOCKED : 0); | |||||
} | } | ||||
void | void | ||||
nm_os_selrecord(struct thread *td, struct nm_selinfo *si) | nm_os_selrecord(struct thread *td, struct nm_selinfo *si) | ||||
{ | { | ||||
selrecord(td, &si->si); | selrecord(td, &si->si); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 241 Lines • Show Last 20 Lines |