VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_main.c@ 62557

Last change on this file since 62557 was 62557, checked in by vboxsync, 9 years ago

bugref:8087: Additions/x11: support non-root X server: only touch VBVA under the lock, as functions which touch VBVA can be called on several threads at once. Also, do not disable VBVA when someone acquires master, as the frame buffer can still send rectangles after that, which re-enables it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.4 KB
Line 
1/* $Id: vbox_main.c 62557 2016-07-26 10:23:12Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on
19 * ast_main.c
20 * with the following copyright and permission notice:
21 *
22 * Copyright 2012 Red Hat Inc.
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a
25 * copy of this software and associated documentation files (the
26 * "Software"), to deal in the Software without restriction, including
27 * without limitation the rights to use, copy, modify, merge, publish,
28 * distribute, sub license, and/or sell copies of the Software, and to
29 * permit persons to whom the Software is furnished to do so, subject to
30 * the following conditions:
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
35 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
36 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
37 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
38 * USE OR OTHER DEALINGS IN THE SOFTWARE.
39 *
40 * The above copyright notice and this permission notice (including the
41 * next paragraph) shall be included in all copies or substantial portions
42 * of the Software.
43 *
44 */
45/*
46 * Authors: Dave Airlie <airlied@redhat.com>
47 */
48#include "vbox_drv.h"
49
50#include <VBox/VBoxVideoGuest.h>
51#include <VBox/VBoxVideo.h>
52
53#include <drm/drm_fb_helper.h>
54#include <drm/drm_crtc_helper.h>
55
56static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
57{
58 struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
59 if (vbox_fb->obj)
60 drm_gem_object_unreference_unlocked(vbox_fb->obj);
61
62 LogFunc(("vboxvideo: %d: vbox_fb=%p, vbox_fb->obj=%p\n", __LINE__,
63 vbox_fb, vbox_fb->obj));
64 drm_framebuffer_cleanup(fb);
65 kfree(fb);
66}
67
68void vbox_enable_accel(struct vbox_private *vbox)
69{
70 unsigned i;
71 struct VBVABUFFER *vbva;
72
73 AssertLogRelReturnVoid(vbox->vbva_info != NULL);
74 for (i = 0; i < vbox->num_crtcs; ++i) {
75 if (vbox->vbva_info[i].pVBVA == NULL) {
76 LogFunc(("vboxvideo: enabling VBVA.\n"));
77 vbva = (struct VBVABUFFER *) ( ((uint8_t *)vbox->mapped_vram)
78 + vbox->vram_host_offset
79 + i * VBVA_MIN_BUFFER_SIZE);
80 if (!VBoxVBVAEnable(&vbox->vbva_info[i], &vbox->submit_info, vbva, i))
81 AssertReleaseMsgFailed(("VBoxVBVAEnable failed - heap allocation error, very old host or driver error.\n"));
82 }
83 }
84}
85
86void vbox_disable_accel(struct vbox_private *vbox)
87{
88 unsigned i;
89
90 for (i = 0; i < vbox->num_crtcs; ++i)
91 VBoxVBVADisable(&vbox->vbva_info[i], &vbox->submit_info, i);
92}
93
94void vbox_enable_caps(struct vbox_private *vbox)
95{
96 uint32_t caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION
97 | VBVACAPS_IRQ
98 | VBVACAPS_USE_VBVA_ONLY;
99 if (vbox->initial_mode_queried)
100 caps |= VBVACAPS_VIDEO_MODE_HINTS;
101 VBoxHGSMISendCapsInfo(&vbox->submit_info, caps);
102}
103
104/** Send information about dirty rectangles to VBVA. If necessary we enable
105 * VBVA first, as this is normally disabled after a change of master in case
106 * the new master does not send dirty rectangle information (is this even
107 * allowed?) */
108void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
109 struct drm_clip_rect *rects,
110 unsigned num_rects)
111{
112 struct vbox_private *vbox = fb->dev->dev_private;
113 struct drm_crtc *crtc;
114 unsigned i;
115
116 LogFunc(("vboxvideo: %d: fb=%p, num_rects=%u, vbox=%p\n", __LINE__, fb,
117 num_rects, vbox));
118 mutex_lock(&vbox->hw_mutex);
119 list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
120 if (CRTC_FB(crtc) == fb) {
121 vbox_enable_accel(vbox);
122 for (i = 0; i < num_rects; ++i)
123 {
124 unsigned crtc_id = to_vbox_crtc(crtc)->crtc_id;
125 VBVACMDHDR cmd_hdr;
126
127 if ( rects[i].x1 > crtc->x
128 + crtc->hwmode.hdisplay
129 || rects[i].y1 > crtc->y
130 + crtc->hwmode.vdisplay
131 || rects[i].x2 < crtc->x
132 || rects[i].y2 < crtc->y)
133 continue;
134 cmd_hdr.x = (int16_t)rects[i].x1;
135 cmd_hdr.y = (int16_t)rects[i].y1;
136 cmd_hdr.w = (uint16_t)rects[i].x2 - rects[i].x1;
137 cmd_hdr.h = (uint16_t)rects[i].y2 - rects[i].y1;
138 if (VBoxVBVABufferBeginUpdate(&vbox->vbva_info[crtc_id],
139 &vbox->submit_info))
140 {
141 VBoxVBVAWrite(&vbox->vbva_info[crtc_id], &vbox->submit_info, &cmd_hdr,
142 sizeof(cmd_hdr));
143 VBoxVBVABufferEndUpdate(&vbox->vbva_info[crtc_id]);
144 }
145 }
146 }
147 }
148 mutex_unlock(&vbox->hw_mutex);
149 LogFunc(("vboxvideo: %d\n", __LINE__));
150}
151
152static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
153 struct drm_file *file_priv,
154 unsigned flags, unsigned color,
155 struct drm_clip_rect *rects,
156 unsigned num_rects)
157{
158 vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
159 return 0;
160}
161
162static const struct drm_framebuffer_funcs vbox_fb_funcs = {
163 .destroy = vbox_user_framebuffer_destroy,
164 .dirty = vbox_user_framebuffer_dirty,
165};
166
167
168int vbox_framebuffer_init(struct drm_device *dev,
169 struct vbox_framebuffer *vbox_fb,
170#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
171 const
172#endif
173 struct DRM_MODE_FB_CMD *mode_cmd,
174 struct drm_gem_object *obj)
175{
176 int ret;
177
178 LogFunc(("vboxvideo: %d: dev=%p, vbox_fb=%p, obj=%p\n", __LINE__, dev,
179 vbox_fb, obj));
180 drm_helper_mode_fill_fb_struct(&vbox_fb->base, mode_cmd);
181 vbox_fb->obj = obj;
182 ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
183 if (ret) {
184 DRM_ERROR("framebuffer init failed %d\n", ret);
185 LogFunc(("vboxvideo: %d\n", __LINE__));
186 return ret;
187 }
188 LogFunc(("vboxvideo: %d\n", __LINE__));
189 return 0;
190}
191
192static struct drm_framebuffer *
193vbox_user_framebuffer_create(struct drm_device *dev,
194 struct drm_file *filp,
195#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
196 const
197#endif
198 struct drm_mode_fb_cmd2 *mode_cmd)
199{
200 struct drm_gem_object *obj;
201 struct vbox_framebuffer *vbox_fb;
202 int ret;
203
204 LogFunc(("vboxvideo: %d\n", __LINE__));
205#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
206 obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
207#else
208 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
209#endif
210 if (obj == NULL)
211 return ERR_PTR(-ENOENT);
212
213 vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
214 if (!vbox_fb) {
215 drm_gem_object_unreference_unlocked(obj);
216 return ERR_PTR(-ENOMEM);
217 }
218
219 ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
220 if (ret) {
221 drm_gem_object_unreference_unlocked(obj);
222 kfree(vbox_fb);
223 return ERR_PTR(ret);
224 }
225 LogFunc(("vboxvideo: %d\n", __LINE__));
226 return &vbox_fb->base;
227}
228
229static const struct drm_mode_config_funcs vbox_mode_funcs = {
230 .fb_create = vbox_user_framebuffer_create,
231};
232
233static void vbox_accel_fini(struct vbox_private *vbox)
234{
235 if (vbox->vbva_info)
236 {
237 vbox_disable_accel(vbox);
238 kfree(vbox->vbva_info);
239 vbox->vbva_info = NULL;
240 }
241}
242
243static int vbox_accel_init(struct vbox_private *vbox)
244{
245 unsigned i;
246 LogFunc(("vboxvideo: %d: vbox=%p, vbox->num_crtcs=%u, vbox->vbva_info=%p\n",
247 __LINE__, vbox, (unsigned)vbox->num_crtcs, vbox->vbva_info));
248 if (!vbox->vbva_info)
249 {
250 vbox->vbva_info = kzalloc( sizeof(struct VBVABUFFERCONTEXT)
251 * vbox->num_crtcs,
252 GFP_KERNEL);
253 if (!vbox->vbva_info)
254 return -ENOMEM;
255 }
256 /* Take a command buffer for each screen from the end of usable VRAM. */
257 vbox->vram_host_offset = (VBOX_MAX_SCREENS - vbox->num_crtcs) * VBVA_MIN_BUFFER_SIZE;
258 vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
259 for (i = 0; i < vbox->num_crtcs; ++i)
260 VBoxVBVASetupBufferContext(&vbox->vbva_info[i],
261 vbox->available_vram_size + i * VBVA_MIN_BUFFER_SIZE,
262 VBVA_MIN_BUFFER_SIZE);
263 LogFunc(("vboxvideo: %d: vbox->vbva_info=%p, vbox->available_vram_size=%u\n",
264 __LINE__, vbox->vbva_info, (unsigned)vbox->available_vram_size));
265 return 0;
266}
267
268/** Allocation function for the HGSMI heap and data. */
269static DECLCALLBACK(void *) alloc_hgsmi_environ(void *environ, HGSMISIZE size)
270{
271 NOREF(environ);
272 return kmalloc(size, GFP_KERNEL);
273}
274
275
276/** Free function for the HGSMI heap and data. */
277static DECLCALLBACK(void) free_hgsmi_environ(void *environ, void *ptr)
278{
279 NOREF(environ);
280 kfree(ptr);
281}
282
283
284/** Pointers to the HGSMI heap and data manipulation functions. */
285static HGSMIENV hgsmi_environ =
286{
287 NULL,
288 alloc_hgsmi_environ,
289 free_hgsmi_environ
290};
291
292
293/** Do we support the 4.3 plus mode hint reporting interface? */
294static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
295{
296 uint32_t have_hints, have_cursor;
297
298 return RT_SUCCESS(VBoxQueryConfHGSMI(&vbox->submit_info, VBOX_VBVA_CONF32_MODE_HINT_REPORTING, &have_hints))
299 && RT_SUCCESS(VBoxQueryConfHGSMI(&vbox->submit_info, VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING, &have_cursor))
300 && have_hints == VINF_SUCCESS
301 && have_cursor == VINF_SUCCESS;
302}
303
304#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
305# define pci_iomap_range(dev, bar, offset, maxlen) \
306 ioremap(pci_resource_start(dev, bar) + offset, maxlen)
307#endif
308
309/** Set up our heaps and data exchange buffers in VRAM before handing the rest
310 * to the memory manager. */
311static int vbox_hw_init(struct vbox_private *vbox)
312{
313 uint32_t base_offset, map_start, guest_heap_offset, guest_heap_size, host_flags_offset;
314 void *guest_heap;
315
316 vbox->full_vram_size = VBoxVideoGetVRAMSize();
317 vbox->any_pitch = VBoxVideoAnyWidthAllowed();
318 DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
319 VBoxHGSMIGetBaseMappingInfo(vbox->full_vram_size, &base_offset, NULL,
320 &guest_heap_offset, &guest_heap_size, &host_flags_offset);
321 map_start = (uint32_t)max((int)base_offset
322 - VBOX_MAX_SCREENS * VBVA_MIN_BUFFER_SIZE, 0);
323 vbox->mapped_vram = pci_iomap_range(vbox->dev->pdev, 0, map_start,
324 vbox->full_vram_size - map_start);
325 if (!vbox->mapped_vram)
326 return -ENOMEM;
327 guest_heap = ((uint8_t *)vbox->mapped_vram) + base_offset - map_start
328 + guest_heap_offset;
329 vbox->host_flags_offset = base_offset - map_start + host_flags_offset;
330 if (RT_FAILURE(VBoxHGSMISetupGuestContext(&vbox->submit_info, guest_heap,
331 guest_heap_size,
332 base_offset + guest_heap_offset,
333 &hgsmi_environ)))
334 return -ENOMEM;
335 /* Reduce available VRAM size to reflect the guest heap. */
336 vbox->available_vram_size = base_offset;
337 /* Linux drm represents monitors as a 32-bit array. */
338 vbox->num_crtcs = min(VBoxHGSMIGetMonitorCount(&vbox->submit_info),
339 (uint32_t)VBOX_MAX_SCREENS);
340 if (!have_hgsmi_mode_hints(vbox))
341 return -ENOTSUPP;
342 vbox->last_mode_hints = kzalloc(sizeof(VBVAMODEHINT) * vbox->num_crtcs, GFP_KERNEL);
343 if (!vbox->last_mode_hints)
344 return -ENOMEM;
345 return vbox_accel_init(vbox);
346}
347
348static void vbox_hw_fini(struct vbox_private *vbox)
349{
350 vbox_accel_fini(vbox);
351 if (vbox->last_mode_hints)
352 kfree(vbox->last_mode_hints);
353 vbox->last_mode_hints = NULL;
354}
355
356int vbox_driver_load(struct drm_device *dev, unsigned long flags)
357{
358 struct vbox_private *vbox;
359 int ret = 0;
360
361 LogFunc(("vboxvideo: %d: dev=%p\n", __LINE__, dev));
362 if (!VBoxHGSMIIsSupported())
363 return -ENODEV;
364 vbox = kzalloc(sizeof(struct vbox_private), GFP_KERNEL);
365 if (!vbox)
366 return -ENOMEM;
367
368 dev->dev_private = vbox;
369 vbox->dev = dev;
370
371 mutex_init(&vbox->hw_mutex);
372
373 ret = vbox_hw_init(vbox);
374 if (ret)
375 goto out_free;
376
377 ret = vbox_mm_init(vbox);
378 if (ret)
379 goto out_free;
380
381 drm_mode_config_init(dev);
382
383 dev->mode_config.funcs = (void *)&vbox_mode_funcs;
384 dev->mode_config.min_width = 64;
385 dev->mode_config.min_height = 64;
386 dev->mode_config.preferred_depth = 24;
387 dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
388 dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
389
390 ret = vbox_mode_init(dev);
391 if (ret)
392 goto out_free;
393
394 ret = vbox_irq_init(vbox);
395 if (ret)
396 goto out_free;
397
398 ret = vbox_fbdev_init(dev);
399 if (ret)
400 goto out_free;
401 LogFunc(("vboxvideo: %d: vbox=%p, vbox->mapped_vram=%p, vbox->full_vram_size=%u\n",
402 __LINE__, vbox, vbox->mapped_vram, (unsigned)vbox->full_vram_size));
403 return 0;
404out_free:
405 vbox_driver_unload(dev);
406 LogFunc(("vboxvideo: %d: ret=%d\n", __LINE__, ret));
407 return ret;
408}
409
410int vbox_driver_unload(struct drm_device *dev)
411{
412 struct vbox_private *vbox = dev->dev_private;
413
414 LogFunc(("vboxvideo: %d\n", __LINE__));
415 vbox_fbdev_fini(dev);
416 vbox_irq_fini(vbox);
417 vbox_mode_fini(dev);
418 if (dev->mode_config.funcs)
419 drm_mode_config_cleanup(dev);
420
421 vbox_hw_fini(vbox);
422 vbox_mm_fini(vbox);
423 if (vbox->mapped_vram)
424 pci_iounmap(dev->pdev, vbox->mapped_vram);
425 kfree(vbox);
426 dev->dev_private = NULL;
427 LogFunc(("vboxvideo: %d\n", __LINE__));
428 return 0;
429}
430
431/** @note this is described in the DRM framework documentation. AST does not
432 * have it, but we get an oops on driver unload if it is not present. */
433void vbox_driver_lastclose(struct drm_device *dev)
434{
435 struct vbox_private *vbox = dev->dev_private;
436
437#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
438 if (vbox->fbdev)
439 drm_fb_helper_restore_fbdev_mode_unlocked(&vbox->fbdev->helper);
440#else
441 drm_modeset_lock_all(dev);
442 if (vbox->fbdev)
443 drm_fb_helper_restore_fbdev_mode(&vbox->fbdev->helper);
444 drm_modeset_unlock_all(dev);
445#endif
446}
447
448int vbox_gem_create(struct drm_device *dev,
449 u32 size, bool iskernel,
450 struct drm_gem_object **obj)
451{
452 struct vbox_bo *vboxbo;
453 int ret;
454
455 LogFunc(("vboxvideo: %d: dev=%p, size=%u, iskernel=%u\n", __LINE__,
456 dev, (unsigned)size, (unsigned)iskernel));
457 *obj = NULL;
458
459 size = roundup(size, PAGE_SIZE);
460 if (size == 0)
461 return -EINVAL;
462
463 ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
464 if (ret) {
465 if (ret != -ERESTARTSYS)
466 DRM_ERROR("failed to allocate GEM object\n");
467 return ret;
468 }
469 *obj = &vboxbo->gem;
470 LogFunc(("vboxvideo: %d: obj=%p\n", __LINE__, obj));
471 return 0;
472}
473
474int vbox_dumb_create(struct drm_file *file,
475 struct drm_device *dev,
476 struct drm_mode_create_dumb *args)
477{
478 int ret;
479 struct drm_gem_object *gobj;
480 u32 handle;
481
482 LogFunc(("vboxvideo: %d: args->width=%u, args->height=%u, args->bpp=%u\n",
483 __LINE__, (unsigned)args->width, (unsigned)args->height,
484 (unsigned)args->bpp));
485 args->pitch = args->width * ((args->bpp + 7) / 8);
486 args->size = args->pitch * args->height;
487
488 ret = vbox_gem_create(dev, args->size, false,
489 &gobj);
490 if (ret)
491 return ret;
492
493 ret = drm_gem_handle_create(file, gobj, &handle);
494 drm_gem_object_unreference_unlocked(gobj);
495 if (ret)
496 return ret;
497
498 args->handle = handle;
499 LogFunc(("vboxvideo: %d: args->handle=%u\n", __LINE__,
500 (unsigned)args->handle));
501 return 0;
502}
503
504#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
505int vbox_dumb_destroy(struct drm_file *file,
506 struct drm_device *dev,
507 uint32_t handle)
508{
509 LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__, dev,
510 (unsigned)handle));
511 return drm_gem_handle_delete(file, handle);
512}
513#endif
514
515static void vbox_bo_unref(struct vbox_bo **bo)
516{
517 struct ttm_buffer_object *tbo;
518
519 if ((*bo) == NULL)
520 return;
521
522 LogFunc(("vboxvideo: %d: bo=%p\n", __LINE__, bo));
523 tbo = &((*bo)->bo);
524 ttm_bo_unref(&tbo);
525 if (tbo == NULL)
526 *bo = NULL;
527
528}
529void vbox_gem_free_object(struct drm_gem_object *obj)
530{
531 struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
532
533 LogFunc(("vboxvideo: %d: vbox_bo=%p\n", __LINE__, vbox_bo));
534 vbox_bo_unref(&vbox_bo);
535}
536
537
538static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
539{
540#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
541 return bo->bo.addr_space_offset;
542#else
543 return drm_vma_node_offset_addr(&bo->bo.vma_node);
544#endif
545}
546int
547vbox_dumb_mmap_offset(struct drm_file *file,
548 struct drm_device *dev,
549 uint32_t handle,
550 uint64_t *offset)
551{
552 struct drm_gem_object *obj;
553 int ret;
554 struct vbox_bo *bo;
555
556 LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__,
557 dev, (unsigned)handle));
558 mutex_lock(&dev->struct_mutex);
559#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
560 obj = drm_gem_object_lookup(file, handle);
561#else
562 obj = drm_gem_object_lookup(dev, file, handle);
563#endif
564 if (obj == NULL) {
565 ret = -ENOENT;
566 goto out_unlock;
567 }
568
569 bo = gem_to_vbox_bo(obj);
570 *offset = vbox_bo_mmap_offset(bo);
571
572 drm_gem_object_unreference(obj);
573 ret = 0;
574 LogFunc(("vboxvideo: %d: bo=%p, *offset=%llu\n", __LINE__,
575 bo, (unsigned long long)*offset));
576out_unlock:
577 mutex_unlock(&dev->struct_mutex);
578 return ret;
579
580}
Note: See TracBrowser for help on using the repository browser.

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