Buffers which can be memory mapped into userspace should never be

freed. Recycle the buffers instead. This patch also fixes a panic at
reboot issue when an UDL adapter is attached to the system.
This commit is contained in:
hselasky 2015-04-17 07:07:06 +00:00
parent 5bf38b8e18
commit c3f2a6832e
2 changed files with 74 additions and 8 deletions

View File

@ -76,6 +76,11 @@ static int udl_fps = 25;
SYSCTL_INT(_hw_usb_udl, OID_AUTO, fps, CTLFLAG_RWTUN,
&udl_fps, 0, "Frames Per Second, 1-60");
static struct mtx udl_buffer_mtx;
static struct udl_buffer_head udl_buffer_head;
MALLOC_DEFINE(M_USB_DL, "USB", "USB DisplayLink");
/*
* Prototypes.
*/
@ -175,6 +180,56 @@ static const STRUCT_USB_HOST_ID udl_devs[] = {
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)}
};
static void
udl_buffer_init(void *arg)
{
mtx_init(&udl_buffer_mtx, "USB", "UDL", MTX_DEF);
TAILQ_INIT(&udl_buffer_head);
}
SYSINIT(udl_buffer_init, SI_SUB_LOCK, SI_ORDER_FIRST, udl_buffer_init, NULL);
CTASSERT(sizeof(struct udl_buffer) < PAGE_SIZE);
static void *
udl_buffer_alloc(uint32_t size)
{
struct udl_buffer *buf;
mtx_lock(&udl_buffer_mtx);
TAILQ_FOREACH(buf, &udl_buffer_head, entry) {
if (buf->size == size) {
TAILQ_REMOVE(&udl_buffer_head, buf, entry);
break;
}
}
mtx_unlock(&udl_buffer_mtx);
if (buf != NULL) {
/* wipe and recycle buffer */
memset(buf, 0, size);
return (buf);
}
/* allocate new buffer */
return (malloc(size, M_USB_DL, M_WAITOK | M_ZERO));
}
static void
udl_buffer_free(void *_buf, uint32_t size)
{
struct udl_buffer *buf;
buf = (struct udl_buffer *)_buf;
if (buf == NULL)
return;
/*
* Memory mapped buffers should never be freed.
* Put display buffer into a recycle list.
*/
mtx_lock(&udl_buffer_mtx);
buf->size = size;
TAILQ_INSERT_TAIL(&udl_buffer_head, buf, entry);
mtx_unlock(&udl_buffer_mtx);
}
static uint32_t
udl_get_fb_size(struct udl_softc *sc)
{
@ -403,11 +458,11 @@ udl_detach(device_t dev)
mtx_destroy(&sc->sc_mtx);
cv_destroy(&sc->sc_cv);
/*
* Free framebuffer memory, if any.
*/
free(sc->sc_fb_addr, M_DEVBUF);
free(sc->sc_fb_copy, M_DEVBUF);
/* put main framebuffer into a recycle list, if any */
udl_buffer_free(sc->sc_fb_addr, sc->sc_fb_size);
/* free shadow framebuffer memory, if any */
free(sc->sc_fb_copy, M_USB_DL);
return (0);
}
@ -782,13 +837,15 @@ udl_fbmem_alloc(struct udl_softc *sc)
size = udl_get_fb_size(sc);
size = round_page(size);
/* check for zero size */
if (size == 0)
size = PAGE_SIZE;
/*
* It is assumed that allocations above PAGE_SIZE bytes will
* be PAGE_SIZE aligned for use with mmap()
*/
sc->sc_fb_addr = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
sc->sc_fb_copy = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
sc->sc_fb_addr = udl_buffer_alloc(size);
sc->sc_fb_copy = malloc(size, M_USB_DL, M_WAITOK | M_ZERO);
sc->sc_fb_size = size;
}

View File

@ -34,6 +34,15 @@
#define UDL_FONT_HEIGHT 16 /* pixels */
#define UDL_MAX_MODES 25 /* units */
MALLOC_DECLARE(M_USB_DL);
struct udl_buffer {
TAILQ_ENTRY(udl_buffer) entry;
uint32_t size;
};
TAILQ_HEAD(udl_buffer_head, udl_buffer);
struct udl_cmd_buf {
TAILQ_ENTRY(udl_cmd_buf) entry;
uint32_t off;