VirtualBox

Changeset 10954 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Jul 29, 2008 7:51:36 PM (16 years ago)
Author:
vboxsync
Message:

IPRT: Integrated vbi v2 changes (r0drv/solaris/vbi).

Location:
trunk/src/VBox/Runtime
Files:
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r10949 r10954  
    11321132
    11331133ifdef VBOX_WITH_SOLARIS_VBI
    1134  ## @todo svn copy r0drv/solaris/mpnotification-r0drv-solaris.c r0drv/solaris/vbi/mpnotification-r0drv-solaris.c
    1135  # and change the first file below.
    11361134 RuntimeR0Drv_SOURCES.solaris += \
    1137         r0drv/solaris/mpnotification-r0drv-solaris.c \
     1135        r0drv/solaris/vbi/mpnotification-r0drv-solaris.c \
    11381136        r0drv/solaris/vbi/alloc-r0drv-solaris.c \
    11391137        r0drv/solaris/vbi/assert-r0drv-solaris.c \
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/i86pc/os/vbi.c

    r9173 r10954  
    2424 */
    2525
    26 #pragma ident   "@(#)vbi.c      1.1     08/05/26 SMI"
     26#pragma ident   "%Z%%M% %I%     %E% SMI"
    2727
    2828/*
     
    7878#pragma weak cpuset_all
    7979#pragma weak cpuset_all_but
     80#pragma weak cpuset_only
    8081
    8182static struct modlmisc vbi_modlmisc = {
     
    159160        void *ptr;
    160161
    161         if ((size >> MMU_PAGESHIFT) << MMU_PAGESHIFT != size)
     162        if ((size & MMU_PAGEOFFSET) != 0)
    162163                return (NULL);
    163164
     
    428429         * hack for a kernel compiled with the different NCPU than this module
    429430         */
     431        ASSERT(curthread->t_preempt >= 1);
    430432        if (use_old_xc_call) {
    431433                hack_set = 0;
    432434                for (i = 0; i < ncpus; ++i)
    433                         hack_set |= 1 << i;
     435                        hack_set |= 1ul << i;
    434436                p_xc_call((xc_arg_t)arg, 0, 0, X_CALL_HIPRI, hack_set,
    435437                    (xc_func_t)func);
     
    451453         * hack for a kernel compiled with the different NCPU than this module
    452454         */
     455        ASSERT(curthread->t_preempt >= 1);
    453456        if (use_old_xc_call) {
    454457                hack_set = 0;
    455458                for (i = 0; i < ncpus; ++i) {
    456459                        if (i != CPU->cpu_id)
    457                                 hack_set |= 1 << i;
     460                                hack_set |= 1ul << i;
    458461                }
    459462                p_xc_call((xc_arg_t)arg, 0, 0, X_CALL_HIPRI, hack_set,
     
    475478         * hack for a kernel compiled with the different NCPU than this module
    476479         */
     480        ASSERT(curthread->t_preempt >= 1);
    477481        if (use_old_xc_call) {
    478                 hack_set = 1 << c;
     482                hack_set = 1ul << c;
    479483                p_xc_call((xc_arg_t)arg, 0, 0, X_CALL_HIPRI, hack_set,
    480484                    (xc_func_t)func);
    481485        } else {
    482                 CPUSET_ALL_BUT(set, c);
     486                CPUSET_ONLY(set, c);
    483487                xc_call((xc_arg_t)arg, 0, 0, X_CALL_HIPRI, set,
    484488                    (xc_func_t)func);
     
    821825
    822826/*
    823  * This is revision 1 of the interface. As more functions are added,
     827 * This is revision 2 of the interface. As more functions are added,
    824828 * they should go after this point in the file and the revision level
    825829 * increased.
    826830 */
    827 uint_t vbi_revision_level = 1;
     831uint_t vbi_revision_level = 2;
     832
     833struct vbi_cpu_watch {
     834        void (*vbi_cpu_func)();
     835        void *vbi_cpu_arg;
     836};
     837
     838static int
     839vbi_watcher(cpu_setup_t state, int cpu, void *arg)
     840{
     841        vbi_cpu_watch_t *w = arg;
     842        int online;
     843
     844        if (state == CPU_ON)
     845                online = 1;
     846        else if (state == CPU_OFF)
     847                online = 0;
     848        else
     849                return (0);
     850        w->vbi_cpu_func(w->vbi_cpu_arg, cpu, online);
     851        return (0);
     852}
     853
     854vbi_cpu_watch_t *
     855vbi_watch_cpus(void (*func)(), void *arg, int current_too)
     856{
     857        int c;
     858        vbi_cpu_watch_t *w;
     859
     860        w = kmem_alloc(sizeof (*w), KM_SLEEP);
     861        w->vbi_cpu_func = func;
     862        w->vbi_cpu_arg = arg;
     863        mutex_enter(&cpu_lock);
     864        register_cpu_setup_func(vbi_watcher, w);
     865        if (current_too) {
     866                for (c = 0; c < ncpus; ++c) {
     867                        if (cpu_is_online(cpu[c]))
     868                                func(arg, c, 1);
     869                }
     870        }
     871        mutex_exit(&cpu_lock);
     872        return (w);
     873}
     874
     875void
     876vbi_ignore_cpus(vbi_cpu_watch_t *w)
     877{
     878        mutex_enter(&cpu_lock);
     879        unregister_cpu_setup_func(vbi_watcher, w);
     880        mutex_exit(&cpu_lock);
     881        kmem_free(w, sizeof (*w));
     882}
     883
     884/*
     885 * Simple timers are pretty much a pass through to the cyclic subsystem.
     886 */
     887struct vbi_stimer {
     888        cyc_handler_t   s_handler;
     889        cyc_time_t      s_fire_time;
     890        cyclic_id_t     s_cyclic;
     891        uint64_t        s_tick;
     892        void            (*s_func)(void *, uint64_t);
     893        void            *s_arg;
     894};
     895
     896static void
     897vbi_stimer_func(void *arg)
     898{
     899        vbi_stimer_t *t = arg;
     900        t->s_func(t->s_arg, t->s_tick++);
     901}
     902
     903extern vbi_stimer_t *
     904vbi_stimer_begin(
     905        void (*func)(void *, uint64_t),
     906        void *arg,
     907        uint64_t when,
     908        uint64_t interval,
     909        int on_cpu)
     910{
     911        vbi_stimer_t *t = kmem_zalloc(sizeof (*t), KM_SLEEP);
     912
     913        ASSERT(when < INT64_MAX);
     914        ASSERT(interval < INT64_MAX);
     915        ASSERT(interval + when < INT64_MAX);
     916
     917        t->s_handler.cyh_func = vbi_stimer_func;
     918        t->s_handler.cyh_arg = t;
     919        t->s_handler.cyh_level = CY_LOCK_LEVEL;
     920        t->s_tick = 0;
     921        t->s_func = func;
     922        t->s_arg = arg;
     923
     924        mutex_enter(&cpu_lock);
     925        if (on_cpu != VBI_ANY_CPU && !vbi_cpu_online(on_cpu)) {
     926                t = NULL;
     927                goto done;
     928        }
     929
     930        when += gethrtime();
     931        t->s_fire_time.cyt_when = when;
     932        if (interval == 0)
     933                t->s_fire_time.cyt_interval = INT64_MAX - when;
     934        else
     935                t->s_fire_time.cyt_interval = interval;
     936        t->s_cyclic = cyclic_add(&t->s_handler, &t->s_fire_time);
     937        if (on_cpu != VBI_ANY_CPU)
     938                cyclic_bind(t->s_cyclic, cpu[on_cpu], NULL);
     939done:
     940        mutex_exit(&cpu_lock);
     941        return (t);
     942}
     943
     944extern void
     945vbi_stimer_end(vbi_stimer_t *t)
     946{
     947        ASSERT(t->s_cyclic != CYCLIC_NONE);
     948        mutex_enter(&cpu_lock);
     949        cyclic_remove(t->s_cyclic);
     950        mutex_exit(&cpu_lock);
     951        kmem_free(t, sizeof (*t));
     952}
     953
     954/*
     955 * Global timers are more complicated. They include a counter on the callback,
     956 * that indicates the first call on a given cpu.
     957 */
     958struct vbi_gtimer {
     959        uint64_t        *g_counters;
     960        void            (*g_func)(void *, uint64_t);
     961        void            *g_arg;
     962        uint64_t        g_when;
     963        uint64_t        g_interval;
     964        cyclic_id_t     g_cyclic;
     965};
     966
     967static void
     968vbi_gtimer_func(void *arg)
     969{
     970        vbi_gtimer_t *t = arg;
     971        t->g_func(t->g_arg, t->g_counters[CPU->cpu_id]);
     972}
     973
     974/*
     975 * Whenever a cpu is onlined, need to reset the g_counters[] for it to zero.
     976 */
     977static void
     978vbi_gtimer_online(void *arg, cpu_t *cpu, cyc_handler_t *h, cyc_time_t *ct)
     979{
     980        vbi_gtimer_t *t = arg;
     981        hrtime_t now;
     982
     983        t->g_counters[cpu->cpu_id] = 0;
     984        h->cyh_func = vbi_gtimer_func;
     985        h->cyh_arg = t;
     986        h->cyh_level = CY_LOCK_LEVEL;
     987        now = gethrtime();
     988        if (t->g_when < now)
     989                ct->cyt_when = now + t->g_interval / 2;
     990        else
     991                ct->cyt_when = t->g_when;
     992        ct->cyt_interval = t->g_interval;
     993}
     994
     995
     996vbi_gtimer_t *
     997vbi_gtimer_begin(
     998        void (*func)(void *, uint64_t),
     999        void *arg,
     1000        uint64_t when,
     1001        uint64_t interval)
     1002{
     1003        vbi_gtimer_t *t;
     1004        cyc_omni_handler_t omni;
     1005
     1006        /*
     1007         * one shot global timer is not supported yet.
     1008         */
     1009        if (interval == 0)
     1010                return (NULL);
     1011
     1012        ASSERT(when < INT64_MAX);
     1013        ASSERT(interval < INT64_MAX);
     1014        ASSERT(interval + when < INT64_MAX);
     1015
     1016        t = kmem_zalloc(sizeof (*t), KM_SLEEP);
     1017        t->g_counters = kmem_zalloc(ncpus * sizeof (uint64_t), KM_SLEEP);
     1018        t->g_when = when + gethrtime();
     1019        t->g_interval = interval;
     1020        t->g_arg = arg;
     1021        t->g_func = func;
     1022        t->g_cyclic = CYCLIC_NONE;
     1023
     1024        omni.cyo_online = (void (*)())vbi_gtimer_online;
     1025        omni.cyo_offline = NULL;
     1026        omni.cyo_arg = t;
     1027
     1028        mutex_enter(&cpu_lock);
     1029        t->g_cyclic = cyclic_add_omni(&omni);
     1030        mutex_exit(&cpu_lock);
     1031        return (t);
     1032}
     1033
     1034extern void
     1035vbi_gtimer_end(vbi_gtimer_t *t)
     1036{
     1037        ASSERT(t->g_cyclic != CYCLIC_NONE);
     1038        mutex_enter(&cpu_lock);
     1039        cyclic_remove(t->g_cyclic);
     1040        mutex_exit(&cpu_lock);
     1041        kmem_free(t->g_counters, ncpus * sizeof (uint64_t));
     1042        kmem_free(t, sizeof (*t));
     1043}
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/i86pc/sys/vbi.h

    r9173 r10954  
    2828#define _SYS_VBI_H
    2929
    30 #pragma ident   "@(#)vbi.h      1.1     08/05/26 SMI"
     30#pragma ident   "%Z%%M% %I%     %E% SMI"
    3131
    3232#ifdef  __cplusplus
     
    109109 */
    110110extern uint64_t vbi_timer_granularity(void);
     111
     112/* old timer funcs */
    111113extern void *vbi_timer_create(void *callback, void *arg1, void *arg2,
    112114    uint64_t interval);
     
    222224extern uint_t vbi_revision_level;
    223225
     226/* begin interfaces defined for version 2 */
     227
     228/*
     229 * Install/remove a call back for CPU online/offline event notification.
     230 *
     231 * The call back func is invoked with 3 arguments:
     232 *      void func(void *arg, int cpu, int online);
     233 * - arg is passed through from vbi_watch_cpus()
     234 * - cpu is the CPU id involved
     235 * - online is non-zero for a CPU that comes online and 0 for a CPU that is
     236 *   going offline.
     237 *
     238 * If current_too is non-zero, then a cpu online event will be invoked for all
     239 * currently online CPUs.
     240 *
     241 * Note there is no guarantee about which CPU the function is invoked on.
     242 */
     243typedef struct vbi_cpu_watch vbi_cpu_watch_t;
     244extern vbi_cpu_watch_t *vbi_watch_cpus(void (*func)(), void *arg,
     245    int current_too);
     246extern void vbi_ignore_cpus(vbi_cpu_watch_t *);
     247#pragma weak vbi_watch_cpus
     248#pragma weak vbi_ignore_cpus
     249
     250/*
     251 * New timer interfaces
     252 *
     253 * A simple timer fires just once and on only one cpu. It may be repeating or
     254 * a one shot.
     255 *
     256 * Support for one shot (ie interval == 0) global timers is optional.
     257 *
     258 * For simple timers, if cpu is VBI_ANY_CPU, the timer may fire on any
     259 * available cpu otherwise the timer will fire only on the given cpu
     260 *
     261 * The repeating call back, func, is invoked with 2 arguments:
     262 * - arg is just passed through
     263 * - a uint64_t counter that starts at 0 and increments with each timer event.
     264 *   The count is per-cpu and resets whenever a cpu goes offline and comes back
     265 *   online.
     266 *
     267 * The when parameter is time relative to now.
     268 *
     269 * vbi_stimer_begin() may return NULL if there was an error in
     270 * creating the timer, for example if a requested cpu is not online.
     271 *
     272 * vbi_gtimer_begin() may return NULL when called if it does not
     273 * support the requested kind of timer (ie interval == 0)
     274 */
     275#define VBI_ANY_CPU     (-1)
     276
     277typedef struct vbi_stimer vbi_stimer_t;
     278extern vbi_stimer_t *vbi_stimer_begin(void (*func)(void *, uint64_t), void *arg,
     279    uint64_t when, uint64_t interval, int cpu);
     280extern void vbi_stimer_end(vbi_stimer_t *);
     281#pragma weak vbi_stimer_begin
     282#pragma weak vbi_stimer_end
     283
     284typedef struct vbi_gtimer vbi_gtimer_t;
     285extern vbi_gtimer_t *vbi_gtimer_begin(void (*func)(void *, uint64_t), void *arg,
     286    uint64_t when, uint64_t interval);
     287extern void vbi_gtimer_end(vbi_gtimer_t *);
     288#pragma weak vbi_gtimer_begin
     289#pragma weak vbi_gtimer_end
     290
     291
     292/* end of interfaces defined for version 2 */
     293
    224294#ifdef  __cplusplus
    225295}
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/mp-r0drv-solaris.c

    r9429 r10954  
    229229    RTCPUID idCpu = RTMpCpuId();
    230230
    231     Assert(idCpu != pArgs->idCpu);
     231    Assert(idCpu == pArgs->idCpu);
    232232    pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
    233233    ASMAtomicIncU32(&pArgs->cHits);
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/mpnotification-r0drv-solaris.c

    r10948 r10954  
    3636
    3737#include <iprt/mp.h>
     38#include <iprt/err.h>
    3839#include "r0drv/mp-r0drv.h"
    3940
    4041
    41 static int rtMpNotificationSolarisCallback(cpu_setup_t enmSolarisEvent, int iCpu, void *pvUser)
     42static void rtMpNotificationSolarisCallback(void *pvUser, int iCpu, int online)
    4243{
    4344    NOREF(pvUser);
    4445
    4546    /* ASSUMES iCpu == RTCPUID */
    46     switch (enmSolarisEvent)
    47     {
    48         case CPU_INIT:
    49         case CPU_CONFIG:
    50         case CPU_UNCONFIG:
    51             break;
    52 
    53         case CPU_ON:
    54             rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, iCpu);
    55             break;
    56 
    57         case CPU_OFF:
    58             rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, iCpu);
    59             break;
    60 
    61         case CPU_CPUPART_IN:
    62         case CPU_CPUPART_OUT:
    63             /** @todo are these relevant? */
    64             break;
    65     }
    66     return 0;
     47    if (online)
     48        rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, iCpu);
     49    else
     50        rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, iCpu);
    6751}
    6852
     53static vbi_cpu_watch_t *watch_handle = NULL;
    6954
    7055int rtR0MpNotificationNativeInit(void)
    7156{
    72     register_cpu_setup_func(rtMpNotificationSolarisCallback, NULL);
     57    if (vbi_revision_level < 2)
     58        return VERR_NOT_SUPPORTED;
     59    if (watch_handle != NULL)
     60        return VERR_INVALID_PARAMETER;
     61    watch_handle = vbi_watch_cpus(rtMpNotificationSolarisCallback, NULL, 0);
     62    return VINF_SUCCESS;
    7363}
    7464
     
    7666void rtR0MpNotificationNativeTerm(void)
    7767{
    78     unregister_cpu_setup_func(rtMpNotificationSolarisCallback, NULL);
     68    if (vbi_revision_level >= 2 && watch_handle != NULL)
     69        vbi_ignore_cpus(watch_handle);
     70    watch_handle = NULL;
    7971}
    8072
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/timer-r0drv-solaris.c

    r9444 r10954  
    6060    /** Flag indicating the the timer is suspended. */
    6161    uint8_t volatile        fSuspended;
     62    /** Run on all CPUs if set */
     63    uint8_t                 fAllCpu;
    6264    /** Whether the timer must run on a specific CPU or not. */
    6365    uint8_t                 fSpecificCpu;
    6466    /** The CPU it must run on if fSpecificCpu is set. */
    6567    uint8_t                 iCpu;
    66     /** The Solaris timer handle. */
    67     void                   *handle;
     68    /** The nano second interval for repeating timers */
     69    uint64_t                interval;
     70    /** simple Solaris timer handle. */
     71    vbi_stimer_t            *stimer;
     72    /** global Solaris timer handle. */
     73    vbi_gtimer_t            *gtimer;
    6874    /** The user callback. */
    6975    PFNRTTIMER              pfnTimer;
    70     /** The current tick count. */
    71     uint64_t                iTick;
    72 
     76    /** The argument for the user callback. */
     77    void                    *pvUser;
    7378} RTTIMER;
    7479
    7580
    76 /**
    77  * Callback wrapper for adding the new iTick argument.
    78  *
    79  * @param   pTimer  The timer.
    80  * @param   pvUser  The user argument.
    81  */
    82 static void rtTimerSolarisCallbackWrapper(PRTTIMER pTimer, void *pvUser)
    83 {
    84     pTimer->pfnTimer(pTimer, pvUser, ++pTimer->iTick);
     81/*
     82 * Need a wrapper to get the PRTTIMER passed through
     83 */
     84static void rtTimerSolarisCallbackWrapper(PRTTIMER pTimer, uint64_t tick)
     85{
     86    pTimer->pfnTimer(pTimer, pTimer->pvUser, tick);
    8587}
    8688
     
    9799    if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
    98100        return VERR_INVALID_PARAMETER;
     101    if (vbi_revision_level < 2)
     102        return VERR_NOT_SUPPORTED;
     103
    99104    if (    (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    100         /** @todo implement &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL*/)
     105        &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
     106        &&  !RTMpIsCpuPossible((fFlags & RTTIMER_FLAGS_CPU_MASK)))
     107        return VERR_CPU_NOT_FOUND;
     108
     109    if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL && u64NanoInterval == 0)
    101110        return VERR_NOT_SUPPORTED;
    102111
     
    110119    pTimer->u32Magic = RTTIMER_MAGIC;
    111120    pTimer->fSuspended = true;
    112     pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
    113     pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
    114     pTimer->handle = vbi_timer_create(rtTimerSolarisCallbackWrapper, pTimer, pvUser, u64NanoInterval);
     121    if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
     122    {
     123        pTimer->fAllCpu = true;
     124        pTimer->fSpecificCpu = false;
     125    }
     126    else if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
     127    {
     128        pTimer->fAllCpu = false;
     129        pTimer->fSpecificCpu = true;
     130        pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
     131    }
     132    pTimer->interval = u64NanoInterval;
    115133    pTimer->pfnTimer = pfnTimer;
    116     pTimer->iTick = 0;
     134    pTimer->pvUser = pvUser;
     135    pTimer->stimer = NULL;
     136    pTimer->gtimer = NULL;
    117137
    118138    *ppTimer = pTimer;
     
    145165     * Free the associated resources.
    146166     */
     167    RTTimerStop(pTimer);
    147168    pTimer->u32Magic++;
    148     vbi_timer_stop(pTimer->handle);
    149     vbi_timer_destroy(pTimer->handle);
    150169    RTMemFree(pTimer);
    151170    return VINF_SUCCESS;
     
    155174RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
    156175{
     176    int cpu = VBI_ANY_CPU;
     177
    157178    if (!rtTimerIsValid(pTimer))
    158179        return VERR_INVALID_HANDLE;
     
    160181        return VERR_TIMER_ACTIVE;
    161182
    162     /*
    163      * Calc when it should start firing.
    164      */
    165183    pTimer->fSuspended = false;
    166     vbi_timer_start(pTimer->handle, u64First);
     184    if (pTimer->fAllCpu)
     185    {
     186        pTimer->gtimer = vbi_gtimer_begin(rtTimerSolarisCallbackWrapper, pTimer, u64First, pTimer->interval);
     187        if (pTimer->gtimer == NULL)
     188            return VERR_INVALID_PARAMETER;
     189    }
     190    else
     191    {
     192        if (pTimer->fSpecificCpu)
     193            cpu = pTimer->iCpu;
     194        pTimer->stimer = vbi_stimer_begin(rtTimerSolarisCallbackWrapper, pTimer, u64First, pTimer->interval, cpu);
     195        if (pTimer->stimer == NULL)
     196        {
     197            if (cpu != VBI_ANY_CPU)
     198                return VERR_CPU_OFFLINE;
     199            return VERR_INVALID_PARAMETER;
     200        }
     201    }
    167202
    168203    return VINF_SUCCESS;
     
    177212        return VERR_TIMER_SUSPENDED;
    178213
    179     /*
    180      * Suspend the timer.
    181      */
    182214    pTimer->fSuspended = true;
    183     vbi_timer_stop(pTimer->handle);
     215    if (pTimer->stimer)
     216    {
     217        vbi_stimer_end(pTimer->stimer);
     218        pTimer->stimer = NULL;
     219    }
     220    else if (pTimer->gtimer)
     221    {
     222        vbi_gtimer_end(pTimer->gtimer);
     223        pTimer->gtimer = NULL;
     224    }
    184225
    185226    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette