diff options
| -rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/staging/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/memrar/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/staging/memrar/Makefile | 2 | ||||
| -rw-r--r-- | drivers/staging/memrar/TODO | 43 | ||||
| -rw-r--r-- | drivers/staging/memrar/memrar-abi | 89 | ||||
| -rw-r--r-- | drivers/staging/memrar/memrar.h | 174 | ||||
| -rw-r--r-- | drivers/staging/memrar/memrar_allocator.c | 432 | ||||
| -rw-r--r-- | drivers/staging/memrar/memrar_allocator.h | 149 | ||||
| -rw-r--r-- | drivers/staging/memrar/memrar_handler.c | 1007 |
10 files changed, 0 insertions, 1914 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 18b43fcb4171..dca4a0bb6ca9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
| @@ -117,8 +117,6 @@ source "drivers/staging/hv/Kconfig" | |||
| 117 | 117 | ||
| 118 | source "drivers/staging/vme/Kconfig" | 118 | source "drivers/staging/vme/Kconfig" |
| 119 | 119 | ||
| 120 | source "drivers/staging/memrar/Kconfig" | ||
| 121 | |||
| 122 | source "drivers/staging/sep/Kconfig" | 120 | source "drivers/staging/sep/Kconfig" |
| 123 | 121 | ||
| 124 | source "drivers/staging/iio/Kconfig" | 122 | source "drivers/staging/iio/Kconfig" |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index cfd13cd55efb..eb93012b6f59 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
| @@ -40,7 +40,6 @@ obj-$(CONFIG_VT6655) += vt6655/ | |||
| 40 | obj-$(CONFIG_VT6656) += vt6656/ | 40 | obj-$(CONFIG_VT6656) += vt6656/ |
| 41 | obj-$(CONFIG_HYPERV) += hv/ | 41 | obj-$(CONFIG_HYPERV) += hv/ |
| 42 | obj-$(CONFIG_VME_BUS) += vme/ | 42 | obj-$(CONFIG_VME_BUS) += vme/ |
| 43 | obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ | ||
| 44 | obj-$(CONFIG_DX_SEP) += sep/ | 43 | obj-$(CONFIG_DX_SEP) += sep/ |
| 45 | obj-$(CONFIG_IIO) += iio/ | 44 | obj-$(CONFIG_IIO) += iio/ |
| 46 | obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ | 45 | obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ |
diff --git a/drivers/staging/memrar/Kconfig b/drivers/staging/memrar/Kconfig deleted file mode 100644 index cbeebc550904..000000000000 --- a/drivers/staging/memrar/Kconfig +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | config MRST_RAR_HANDLER | ||
| 2 | tristate "RAR handler driver for Intel Moorestown platform" | ||
| 3 | depends on RAR_REGISTER | ||
| 4 | ---help--- | ||
| 5 | This driver provides a memory management interface to | ||
| 6 | restricted access regions (RAR) available on the Intel | ||
| 7 | Moorestown platform. | ||
| 8 | |||
| 9 | Once locked down, restricted access regions are only | ||
| 10 | accessible by specific hardware on the platform. The x86 | ||
| 11 | CPU is typically not one of those platforms. As such this | ||
| 12 | driver does not access RAR, and only provides a buffer | ||
| 13 | allocation/bookkeeping mechanism. | ||
| 14 | |||
| 15 | If unsure, say N. | ||
diff --git a/drivers/staging/memrar/Makefile b/drivers/staging/memrar/Makefile deleted file mode 100644 index a3336c00cc5f..000000000000 --- a/drivers/staging/memrar/Makefile +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | obj-$(CONFIG_MRST_RAR_HANDLER) += memrar.o | ||
| 2 | memrar-y := memrar_allocator.o memrar_handler.o | ||
diff --git a/drivers/staging/memrar/TODO b/drivers/staging/memrar/TODO deleted file mode 100644 index 435e09ba44c5..000000000000 --- a/drivers/staging/memrar/TODO +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | RAR Handler (memrar) Driver TODO Items | ||
| 2 | ====================================== | ||
| 3 | |||
| 4 | Maintainer: Eugene Epshteyn <eugene.epshteyn@intel.com> | ||
| 5 | |||
| 6 | memrar.h | ||
| 7 | -------- | ||
| 8 | 1. This header exposes the driver's user space and kernel space | ||
| 9 | interfaces. It should be moved to <linux/rar/memrar.h>, or | ||
| 10 | something along those lines, when this memrar driver is moved out | ||
| 11 | of `staging'. | ||
| 12 | a. It would be ideal if staging/rar_register/rar_register.h was | ||
| 13 | moved to the same directory. | ||
| 14 | |||
| 15 | memrar_allocator.[ch] | ||
| 16 | --------------------- | ||
| 17 | 1. Address potential fragmentation issues with the memrar_allocator. | ||
| 18 | |||
| 19 | 2. Hide struct memrar_allocator details/fields. They need not be | ||
| 20 | exposed to the user. | ||
| 21 | a. Forward declare struct memrar_allocator. | ||
| 22 | b. Move all three struct definitions to `memrar_allocator.c' | ||
| 23 | source file. | ||
| 24 | c. Add a memrar_allocator_largest_free_area() function, or | ||
| 25 | something like that to get access to the value of the struct | ||
| 26 | memrar_allocator "largest_free_area" field. This allows the | ||
| 27 | struct memrar_allocator fields to be completely hidden from | ||
| 28 | the user. The memrar_handler code really only needs this for | ||
| 29 | statistic gathering on-demand. | ||
| 30 | d. Do the same for the "capacity" field as the | ||
| 31 | "largest_free_area" field. | ||
| 32 | |||
| 33 | 3. Move memrar_allocator.* to kernel `lib' directory since it is HW | ||
| 34 | neutral. | ||
| 35 | a. Alternatively, use lib/genalloc.c instead. | ||
| 36 | b. A kernel port of Doug Lea's malloc() implementation may also | ||
| 37 | be an option. | ||
| 38 | |||
| 39 | memrar_handler.c | ||
| 40 | ---------------- | ||
| 41 | 1. Split user space interface (ioctl code) from core/kernel code, | ||
| 42 | e.g.: | ||
| 43 | memrar_handler.c -> memrar_core.c, memrar_user.c | ||
diff --git a/drivers/staging/memrar/memrar-abi b/drivers/staging/memrar/memrar-abi deleted file mode 100644 index c23fc996a435..000000000000 --- a/drivers/staging/memrar/memrar-abi +++ /dev/null | |||
| @@ -1,89 +0,0 @@ | |||
| 1 | What: /dev/memrar | ||
| 2 | Date: March 2010 | ||
| 3 | KernelVersion: 2.6.34 | ||
| 4 | Contact: Eugene Epshteyn <eugene.epshteyn@intel.com> | ||
| 5 | Description: The Intel Moorestown Restricted Access Region (RAR) | ||
| 6 | Handler driver exposes an ioctl() based interface that | ||
| 7 | allows a user to reserve and release blocks of RAR | ||
| 8 | memory. | ||
| 9 | |||
| 10 | Note: A sysfs based one was not appropriate for the | ||
| 11 | RAR handler's usage model. | ||
| 12 | |||
| 13 | ========================================================= | ||
| 14 | ioctl() Requests | ||
| 15 | ========================================================= | ||
| 16 | RAR_HANDLER_RESERVE | ||
| 17 | ------------------- | ||
| 18 | Description: Reserve RAR block. | ||
| 19 | Type: struct RAR_block_info | ||
| 20 | Direction: in/out | ||
| 21 | Errors: EINVAL (invalid RAR type or size) | ||
| 22 | ENOMEM (not enough RAR memory) | ||
| 23 | |||
| 24 | RAR_HANDLER_STAT | ||
| 25 | ---------------- | ||
| 26 | Description: Get RAR statistics. | ||
| 27 | Type: struct RAR_stat | ||
| 28 | Direction: in/out | ||
| 29 | Errors: EINVAL (invalid RAR type) | ||
| 30 | |||
| 31 | RAR_HANDLER_RELEASE | ||
| 32 | ------------------- | ||
| 33 | Description: Release previously reserved RAR block. | ||
| 34 | Type: 32 bit unsigned integer | ||
| 35 | (e.g. uint32_t), i.e the RAR "handle". | ||
| 36 | Direction: in | ||
| 37 | Errors: EINVAL (invalid RAR handle) | ||
| 38 | |||
| 39 | |||
| 40 | ========================================================= | ||
| 41 | ioctl() Request Parameter Types | ||
| 42 | ========================================================= | ||
| 43 | The structures referred to above are defined as | ||
| 44 | follows: | ||
| 45 | |||
| 46 | /** | ||
| 47 | * struct RAR_block_info - user space struct that | ||
| 48 | * describes RAR buffer | ||
| 49 | * @type: Type of RAR memory (e.g., | ||
| 50 | * RAR_TYPE_VIDEO or RAR_TYPE_AUDIO) [in] | ||
| 51 | * @size: Requested size of a block in bytes to | ||
| 52 | * be reserved in RAR. [in] | ||
| 53 | * @handle: Handle that can be used to refer to | ||
| 54 | * reserved block. [out] | ||
| 55 | * | ||
| 56 | * This is the basic structure exposed to the user | ||
| 57 | * space that describes a given RAR buffer. It used | ||
| 58 | * as the parameter for the RAR_HANDLER_RESERVE ioctl. | ||
| 59 | * The buffer's underlying bus address is not exposed | ||
| 60 | * to the user. User space code refers to the buffer | ||
| 61 | * entirely by "handle". | ||
| 62 | */ | ||
| 63 | struct RAR_block_info { | ||
| 64 | __u32 type; | ||
| 65 | __u32 size; | ||
| 66 | __u32 handle; | ||
| 67 | }; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * struct RAR_stat - RAR statistics structure | ||
| 71 | * @type: Type of RAR memory (e.g., | ||
| 72 | * RAR_TYPE_VIDEO or | ||
| 73 | * RAR_TYPE_AUDIO) [in] | ||
| 74 | * @capacity: Total size of RAR memory | ||
| 75 | * region. [out] | ||
| 76 | * @largest_block_size: Size of the largest reservable | ||
| 77 | * block. [out] | ||
| 78 | * | ||
| 79 | * This structure is used for RAR_HANDLER_STAT ioctl. | ||
| 80 | */ | ||
| 81 | struct RAR_stat { | ||
| 82 | __u32 type; | ||
| 83 | __u32 capacity; | ||
| 84 | __u32 largest_block_size; | ||
| 85 | }; | ||
| 86 | |||
| 87 | Lastly, the RAR_HANDLER_RELEASE ioctl expects a | ||
| 88 | "handle" to the RAR block of memory. It is a 32 bit | ||
| 89 | unsigned integer. | ||
diff --git a/drivers/staging/memrar/memrar.h b/drivers/staging/memrar/memrar.h deleted file mode 100644 index 0feb73b94c91..000000000000 --- a/drivers/staging/memrar/memrar.h +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * RAR Handler (/dev/memrar) internal driver API. | ||
| 3 | * Copyright (C) 2010 Intel Corporation. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of version 2 of the GNU General | ||
| 7 | * Public License as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be | ||
| 10 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
| 12 | * PURPOSE. See the GNU General Public License for more details. | ||
| 13 | * You should have received a copy of the GNU General Public | ||
| 14 | * License along with this program; if not, write to the Free | ||
| 15 | * Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 16 | * Boston, MA 02111-1307, USA. | ||
| 17 | * The full GNU General Public License is included in this | ||
| 18 | * distribution in the file called COPYING. | ||
| 19 | */ | ||
| 20 | |||
| 21 | |||
| 22 | #ifndef _MEMRAR_H | ||
| 23 | #define _MEMRAR_H | ||
| 24 | |||
| 25 | #include <linux/ioctl.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | |||
| 28 | |||
| 29 | /** | ||
| 30 | * struct RAR_stat - RAR statistics structure | ||
| 31 | * @type: Type of RAR memory (e.g., audio vs. video) | ||
| 32 | * @capacity: Total size of RAR memory region. | ||
| 33 | * @largest_block_size: Size of the largest reservable block. | ||
| 34 | * | ||
| 35 | * This structure is used for RAR_HANDLER_STAT ioctl and for the | ||
| 36 | * RAR_get_stat() user space wrapper function. | ||
| 37 | */ | ||
| 38 | struct RAR_stat { | ||
| 39 | __u32 type; | ||
| 40 | __u32 capacity; | ||
| 41 | __u32 largest_block_size; | ||
| 42 | }; | ||
| 43 | |||
| 44 | |||
| 45 | /** | ||
| 46 | * struct RAR_block_info - user space struct that describes RAR buffer | ||
| 47 | * @type: Type of RAR memory (e.g., audio vs. video) | ||
| 48 | * @size: Requested size of a block to be reserved in RAR. | ||
| 49 | * @handle: Handle that can be used to refer to reserved block. | ||
| 50 | * | ||
| 51 | * This is the basic structure exposed to the user space that | ||
| 52 | * describes a given RAR buffer. The buffer's underlying bus address | ||
| 53 | * is not exposed to the user. User space code refers to the buffer | ||
| 54 | * entirely by "handle". | ||
| 55 | */ | ||
| 56 | struct RAR_block_info { | ||
| 57 | __u32 type; | ||
| 58 | __u32 size; | ||
| 59 | __u32 handle; | ||
| 60 | }; | ||
| 61 | |||
| 62 | |||
| 63 | #define RAR_IOCTL_BASE 0xE0 | ||
| 64 | |||
| 65 | /* Reserve RAR block. */ | ||
| 66 | #define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info) | ||
| 67 | |||
| 68 | /* Release previously reserved RAR block. */ | ||
| 69 | #define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32) | ||
| 70 | |||
| 71 | /* Get RAR stats. */ | ||
| 72 | #define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat) | ||
| 73 | |||
| 74 | |||
| 75 | #ifdef __KERNEL__ | ||
| 76 | |||
| 77 | /* -------------------------------------------------------------- */ | ||
| 78 | /* Kernel Side RAR Handler Interface */ | ||
| 79 | /* -------------------------------------------------------------- */ | ||
| 80 | |||
| 81 | /** | ||
| 82 | * struct RAR_buffer - kernel space struct that describes RAR buffer | ||
| 83 | * @info: structure containing base RAR buffer information | ||
| 84 | * @bus_address: buffer bus address | ||
| 85 | * | ||
| 86 | * Structure that contains all information related to a given block of | ||
| 87 | * memory in RAR. It is generally only used when retrieving RAR | ||
| 88 | * related bus addresses. | ||
| 89 | * | ||
| 90 | * Note: This structure is used only by RAR-enabled drivers, and is | ||
| 91 | * not intended to be exposed to the user space. | ||
| 92 | */ | ||
| 93 | struct RAR_buffer { | ||
| 94 | struct RAR_block_info info; | ||
| 95 | dma_addr_t bus_address; | ||
| 96 | }; | ||
| 97 | |||
| 98 | #if defined(CONFIG_MRST_RAR_HANDLER) | ||
| 99 | /** | ||
| 100 | * rar_reserve() - reserve RAR buffers | ||
| 101 | * @buffers: array of RAR_buffers where type and size of buffers to | ||
| 102 | * reserve are passed in, handle and bus address are | ||
| 103 | * passed out | ||
| 104 | * @count: number of RAR_buffers in the "buffers" array | ||
| 105 | * | ||
| 106 | * This function will reserve buffers in the restricted access regions | ||
| 107 | * of given types. | ||
| 108 | * | ||
| 109 | * It returns the number of successfully reserved buffers. Successful | ||
| 110 | * buffer reservations will have the corresponding bus_address field | ||
| 111 | * set to a non-zero value in the given buffers vector. | ||
| 112 | */ | ||
| 113 | extern size_t rar_reserve(struct RAR_buffer *buffers, | ||
| 114 | size_t count); | ||
| 115 | |||
| 116 | /** | ||
| 117 | * rar_release() - release RAR buffers | ||
| 118 | * @buffers: array of RAR_buffers where handles to buffers to be | ||
| 119 | * released are passed in | ||
| 120 | * @count: number of RAR_buffers in the "buffers" array | ||
| 121 | * | ||
| 122 | * This function will release RAR buffers that were retrieved through | ||
| 123 | * a call to rar_reserve() or rar_handle_to_bus() by decrementing the | ||
| 124 | * reference count. The RAR buffer will be reclaimed when the | ||
| 125 | * reference count drops to zero. | ||
| 126 | * | ||
| 127 | * It returns the number of successfully released buffers. Successful | ||
| 128 | * releases will have their handle field set to zero in the given | ||
| 129 | * buffers vector. | ||
| 130 | */ | ||
| 131 | extern size_t rar_release(struct RAR_buffer *buffers, | ||
| 132 | size_t count); | ||
| 133 | |||
| 134 | /** | ||
| 135 | * rar_handle_to_bus() - convert a vector of RAR handles to bus addresses | ||
| 136 | * @buffers: array of RAR_buffers containing handles to be | ||
| 137 | * converted to bus_addresses | ||
| 138 | * @count: number of RAR_buffers in the "buffers" array | ||
| 139 | |||
| 140 | * This function will retrieve the RAR buffer bus addresses, type and | ||
| 141 | * size corresponding to the RAR handles provided in the buffers | ||
| 142 | * vector. | ||
| 143 | * | ||
| 144 | * It returns the number of successfully converted buffers. The bus | ||
| 145 | * address will be set to 0 for unrecognized handles. | ||
| 146 | * | ||
| 147 | * The reference count for each corresponding buffer in RAR will be | ||
| 148 | * incremented. Call rar_release() when done with the buffers. | ||
| 149 | */ | ||
| 150 | extern size_t rar_handle_to_bus(struct RAR_buffer *buffers, | ||
| 151 | size_t count); | ||
| 152 | |||
| 153 | #else | ||
| 154 | |||
| 155 | extern inline size_t rar_reserve(struct RAR_buffer *buffers, size_t count) | ||
| 156 | { | ||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | extern inline size_t rar_release(struct RAR_buffer *buffers, size_t count) | ||
| 161 | { | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | extern inline size_t rar_handle_to_bus(struct RAR_buffer *buffers, | ||
| 166 | size_t count) | ||
| 167 | { | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | #endif /* MRST_RAR_HANDLER */ | ||
| 172 | #endif /* __KERNEL__ */ | ||
| 173 | |||
| 174 | #endif /* _MEMRAR_H */ | ||
diff --git a/drivers/staging/memrar/memrar_allocator.c b/drivers/staging/memrar/memrar_allocator.c deleted file mode 100644 index a4f8c5846a00..000000000000 --- a/drivers/staging/memrar/memrar_allocator.c +++ /dev/null | |||
| @@ -1,432 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * memrar_allocator 1.0: An allocator for Intel RAR. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General | ||
| 8 | * Public License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be | ||
| 11 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
| 13 | * PURPOSE. See the GNU General Public License for more details. | ||
| 14 | * You should have received a copy of the GNU General Public | ||
| 15 | * License along with this program; if not, write to the Free | ||
| 16 | * Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 17 | * Boston, MA 02111-1307, USA. | ||
| 18 | * The full GNU General Public License is included in this | ||
| 19 | * distribution in the file called COPYING. | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * ------------------------------------------------------------------ | ||
| 23 | * | ||
| 24 | * This simple allocator implementation provides a | ||
| 25 | * malloc()/free()-like interface for reserving space within a | ||
| 26 | * previously reserved block of memory. It is not specific to | ||
| 27 | * any hardware, nor is it coupled with the lower level paging | ||
| 28 | * mechanism. | ||
| 29 | * | ||
| 30 | * The primary goal of this implementation is to provide a means | ||
| 31 | * to partition an arbitrary block of memory without actually | ||
| 32 | * accessing the memory or incurring any hardware side-effects | ||
| 33 | * (e.g. paging). It is, in effect, a bookkeeping mechanism for | ||
| 34 | * buffers. | ||
| 35 | */ | ||
| 36 | |||
| 37 | |||
| 38 | #include "memrar_allocator.h" | ||
| 39 | #include <linux/slab.h> | ||
| 40 | #include <linux/bug.h> | ||
| 41 | #include <linux/kernel.h> | ||
| 42 | |||
| 43 | |||
| 44 | struct memrar_allocator *memrar_create_allocator(unsigned long base, | ||
| 45 | size_t capacity, | ||
| 46 | size_t block_size) | ||
| 47 | { | ||
| 48 | struct memrar_allocator *allocator = NULL; | ||
| 49 | struct memrar_address_ranges *first_node = NULL; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Make sure the base address is aligned on a block_size | ||
| 53 | * boundary. | ||
| 54 | * | ||
| 55 | * @todo Is this necessary? | ||
| 56 | */ | ||
| 57 | /* base = ALIGN(base, block_size); */ | ||
| 58 | |||
| 59 | /* Validate parameters. | ||
| 60 | * | ||
| 61 | * Make sure we can allocate the entire memory space. Zero | ||
| 62 | * capacity or block size are obviously invalid. | ||
| 63 | */ | ||
| 64 | if (base == 0 | ||
| 65 | || capacity == 0 | ||
| 66 | || block_size == 0 | ||
| 67 | || ULONG_MAX - capacity < base | ||
| 68 | || capacity < block_size) | ||
| 69 | return allocator; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * There isn't much point in creating a memory allocator that | ||
| 73 | * is only capable of holding one block but we'll allow it, | ||
| 74 | * and issue a diagnostic. | ||
| 75 | */ | ||
| 76 | WARN(capacity < block_size * 2, | ||
| 77 | "memrar: Only one block available to allocator.\n"); | ||
| 78 | |||
| 79 | allocator = kmalloc(sizeof(*allocator), GFP_KERNEL); | ||
| 80 | |||
| 81 | if (allocator == NULL) | ||
| 82 | return allocator; | ||
| 83 | |||
| 84 | mutex_init(&allocator->lock); | ||
| 85 | allocator->base = base; | ||
| 86 | |||
| 87 | /* Round the capacity down to a multiple of block_size. */ | ||
| 88 | allocator->capacity = (capacity / block_size) * block_size; | ||
| 89 | |||
| 90 | allocator->block_size = block_size; | ||
| 91 | |||
| 92 | allocator->largest_free_area = allocator->capacity; | ||
| 93 | |||
| 94 | /* Initialize the handle and free lists. */ | ||
| 95 | INIT_LIST_HEAD(&allocator->allocated_list.list); | ||
| 96 | INIT_LIST_HEAD(&allocator->free_list.list); | ||
| 97 | |||
| 98 | first_node = kmalloc(sizeof(*first_node), GFP_KERNEL); | ||
| 99 | if (first_node == NULL) { | ||
| 100 | kfree(allocator); | ||
| 101 | allocator = NULL; | ||
| 102 | } else { | ||
| 103 | /* Full range of blocks is available. */ | ||
| 104 | first_node->range.begin = base; | ||
| 105 | first_node->range.end = base + allocator->capacity; | ||
| 106 | list_add(&first_node->list, | ||
| 107 | &allocator->free_list.list); | ||
| 108 | } | ||
| 109 | |||
| 110 | return allocator; | ||
| 111 | } | ||
| 112 | |||
| 113 | void memrar_destroy_allocator(struct memrar_allocator *allocator) | ||
| 114 | { | ||
| 115 | /* | ||
| 116 | * Assume that the memory allocator lock isn't held at this | ||
| 117 | * point in time. Caller must ensure that. | ||
| 118 | */ | ||
| 119 | |||
| 120 | struct memrar_address_ranges *pos = NULL; | ||
| 121 | struct memrar_address_ranges *n = NULL; | ||
| 122 | |||
| 123 | if (allocator == NULL) | ||
| 124 | return; | ||
| 125 | |||
| 126 | mutex_lock(&allocator->lock); | ||
| 127 | |||
| 128 | /* Reclaim free list resources. */ | ||
| 129 | list_for_each_entry_safe(pos, | ||
| 130 | n, | ||
| 131 | &allocator->free_list.list, | ||
| 132 | list) { | ||
| 133 | list_del(&pos->list); | ||
| 134 | kfree(pos); | ||
| 135 | } | ||
| 136 | |||
| 137 | mutex_unlock(&allocator->lock); | ||
| 138 | |||
| 139 | kfree(allocator); | ||
| 140 | } | ||
| 141 | |||
| 142 | unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator, | ||
| 143 | size_t size) | ||
| 144 | { | ||
| 145 | struct memrar_address_ranges *pos = NULL; | ||
| 146 | |||
| 147 | size_t num_blocks; | ||
| 148 | unsigned long reserved_bytes; | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Address of allocated buffer. We assume that zero is not a | ||
| 152 | * valid address. | ||
| 153 | */ | ||
| 154 | unsigned long addr = 0; | ||
| 155 | |||
| 156 | if (allocator == NULL || size == 0) | ||
| 157 | return addr; | ||
| 158 | |||
| 159 | /* Reserve enough blocks to hold the amount of bytes requested. */ | ||
| 160 | num_blocks = DIV_ROUND_UP(size, allocator->block_size); | ||
| 161 | |||
| 162 | reserved_bytes = num_blocks * allocator->block_size; | ||
| 163 | |||
| 164 | mutex_lock(&allocator->lock); | ||
| 165 | |||
| 166 | if (reserved_bytes > allocator->largest_free_area) { | ||
| 167 | mutex_unlock(&allocator->lock); | ||
| 168 | return addr; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Iterate through the free list to find a suitably sized | ||
| 173 | * range of free contiguous memory blocks. | ||
| 174 | * | ||
| 175 | * We also take the opportunity to reset the size of the | ||
| 176 | * largest free area size statistic. | ||
| 177 | */ | ||
| 178 | list_for_each_entry(pos, &allocator->free_list.list, list) { | ||
| 179 | struct memrar_address_range * const fr = &pos->range; | ||
| 180 | size_t const curr_size = fr->end - fr->begin; | ||
| 181 | |||
| 182 | if (curr_size >= reserved_bytes && addr == 0) { | ||
| 183 | struct memrar_address_range *range = NULL; | ||
| 184 | struct memrar_address_ranges * const new_node = | ||
| 185 | kmalloc(sizeof(*new_node), GFP_KERNEL); | ||
| 186 | |||
| 187 | if (new_node == NULL) | ||
| 188 | break; | ||
| 189 | |||
| 190 | list_add(&new_node->list, | ||
| 191 | &allocator->allocated_list.list); | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Carve out area of memory from end of free | ||
| 195 | * range. | ||
| 196 | */ | ||
| 197 | range = &new_node->range; | ||
| 198 | range->end = fr->end; | ||
| 199 | fr->end -= reserved_bytes; | ||
| 200 | range->begin = fr->end; | ||
| 201 | addr = range->begin; | ||
| 202 | |||
| 203 | /* | ||
| 204 | * Check if largest area has decreased in | ||
| 205 | * size. We'll need to continue scanning for | ||
| 206 | * the next largest area if it has. | ||
| 207 | */ | ||
| 208 | if (curr_size == allocator->largest_free_area) | ||
| 209 | allocator->largest_free_area -= | ||
| 210 | reserved_bytes; | ||
| 211 | else | ||
| 212 | break; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Reset largest free area size statistic as needed, | ||
| 217 | * but only if we've actually allocated memory. | ||
| 218 | */ | ||
| 219 | if (addr != 0 | ||
| 220 | && curr_size > allocator->largest_free_area) { | ||
| 221 | allocator->largest_free_area = curr_size; | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | mutex_unlock(&allocator->lock); | ||
| 227 | |||
| 228 | return addr; | ||
| 229 | } | ||
| 230 | |||
| 231 | long memrar_allocator_free(struct memrar_allocator *allocator, | ||
| 232 | unsigned long addr) | ||
| 233 | { | ||
| 234 | struct list_head *pos = NULL; | ||
| 235 | struct list_head *tmp = NULL; | ||
| 236 | struct list_head *dst = NULL; | ||
| 237 | |||
| 238 | struct memrar_address_ranges *allocated = NULL; | ||
| 239 | struct memrar_address_range const *handle = NULL; | ||
| 240 | |||
| 241 | unsigned long old_end = 0; | ||
| 242 | unsigned long new_chunk_size = 0; | ||
| 243 | |||
| 244 | if (allocator == NULL) | ||
| 245 | return -EINVAL; | ||
| 246 | |||
| 247 | if (addr == 0) | ||
| 248 | return 0; /* Ignore "free(0)". */ | ||
| 249 | |||
| 250 | mutex_lock(&allocator->lock); | ||
| 251 | |||
| 252 | /* Find the corresponding handle. */ | ||
| 253 | list_for_each_entry(allocated, | ||
| 254 | &allocator->allocated_list.list, | ||
| 255 | list) { | ||
| 256 | if (allocated->range.begin == addr) { | ||
| 257 | handle = &allocated->range; | ||
| 258 | break; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | /* No such buffer created by this allocator. */ | ||
| 263 | if (handle == NULL) { | ||
| 264 | mutex_unlock(&allocator->lock); | ||
| 265 | return -EFAULT; | ||
| 266 | } | ||
| 267 | |||
| 268 | /* | ||
| 269 | * Coalesce adjacent chunks of memory if possible. | ||
| 270 | * | ||
| 271 | * @note This isn't full blown coalescing since we're only | ||
| 272 | * coalescing at most three chunks of memory. | ||
| 273 | */ | ||
| 274 | list_for_each_safe(pos, tmp, &allocator->free_list.list) { | ||
| 275 | /* @todo O(n) performance. Optimize. */ | ||
| 276 | |||
| 277 | struct memrar_address_range * const chunk = | ||
| 278 | &list_entry(pos, | ||
| 279 | struct memrar_address_ranges, | ||
| 280 | list)->range; | ||
| 281 | |||
| 282 | /* Extend size of existing free adjacent chunk. */ | ||
| 283 | if (chunk->end == handle->begin) { | ||
| 284 | /* | ||
| 285 | * Chunk "less than" than the one we're | ||
| 286 | * freeing is adjacent. | ||
| 287 | * | ||
| 288 | * Before: | ||
| 289 | * | ||
| 290 | * +-----+------+ | ||
| 291 | * |chunk|handle| | ||
| 292 | * +-----+------+ | ||
| 293 | * | ||
| 294 | * After: | ||
| 295 | * | ||
| 296 | * +------------+ | ||
| 297 | * | chunk | | ||
| 298 | * +------------+ | ||
| 299 | */ | ||
| 300 | |||
| 301 | struct memrar_address_ranges const * const next = | ||
| 302 | list_entry(pos->next, | ||
| 303 | struct memrar_address_ranges, | ||
| 304 | list); | ||
| 305 | |||
| 306 | chunk->end = handle->end; | ||
| 307 | |||
| 308 | /* | ||
| 309 | * Now check if next free chunk is adjacent to | ||
| 310 | * the current extended free chunk. | ||
| 311 | * | ||
| 312 | * Before: | ||
| 313 | * | ||
| 314 | * +------------+----+ | ||
| 315 | * | chunk |next| | ||
| 316 | * +------------+----+ | ||
| 317 | * | ||
| 318 | * After: | ||
| 319 | * | ||
| 320 | * +-----------------+ | ||
| 321 | * | chunk | | ||
| 322 | * +-----------------+ | ||
| 323 | */ | ||
| 324 | if (!list_is_singular(pos) | ||
| 325 | && chunk->end == next->range.begin) { | ||
| 326 | chunk->end = next->range.end; | ||
| 327 | list_del(pos->next); | ||
| 328 | kfree(next); | ||
| 329 | } | ||
| 330 | |||
| 331 | list_del(&allocated->list); | ||
| 332 | |||
| 333 | new_chunk_size = chunk->end - chunk->begin; | ||
| 334 | |||
| 335 | goto exit_memrar_free; | ||
| 336 | |||
| 337 | } else if (handle->end == chunk->begin) { | ||
| 338 | /* | ||
| 339 | * Chunk "greater than" than the one we're | ||
| 340 | * freeing is adjacent. | ||
| 341 | * | ||
| 342 | * +------+-----+ | ||
| 343 | * |handle|chunk| | ||
| 344 | * +------+-----+ | ||
| 345 | * | ||
| 346 | * After: | ||
| 347 | * | ||
| 348 | * +------------+ | ||
| 349 | * | chunk | | ||
| 350 | * +------------+ | ||
| 351 | */ | ||
| 352 | |||
| 353 | struct memrar_address_ranges const * const prev = | ||
| 354 | list_entry(pos->prev, | ||
| 355 | struct memrar_address_ranges, | ||
| 356 | list); | ||
| 357 | |||
| 358 | chunk->begin = handle->begin; | ||
| 359 | |||
| 360 | /* | ||
| 361 | * Now check if previous free chunk is | ||
| 362 | * adjacent to the current extended free | ||
| 363 | * chunk. | ||
| 364 | * | ||
| 365 | * | ||
| 366 | * Before: | ||
| 367 | * | ||
| 368 | * +----+------------+ | ||
| 369 | * |prev| chunk | | ||
| 370 | * +----+------------+ | ||
| 371 | * | ||
| 372 | * After: | ||
| 373 | * | ||
| 374 | * +-----------------+ | ||
| 375 | * | chunk | | ||
| 376 | * +-----------------+ | ||
| 377 | */ | ||
| 378 | if (!list_is_singular(pos) | ||
| 379 | && prev->range.end == chunk->begin) { | ||
| 380 | chunk->begin = prev->range.begin; | ||
| 381 | list_del(pos->prev); | ||
| 382 | kfree(prev); | ||
| 383 | } | ||
| 384 | |||
| 385 | list_del(&allocated->list); | ||
| 386 | |||
| 387 | new_chunk_size = chunk->end - chunk->begin; | ||
| 388 | |||
| 389 | goto exit_memrar_free; | ||
| 390 | |||
| 391 | } else if (chunk->end < handle->begin | ||
| 392 | && chunk->end > old_end) { | ||
| 393 | /* Keep track of where the entry could be | ||
| 394 | * potentially moved from the "allocated" list | ||
| 395 | * to the "free" list if coalescing doesn't | ||
| 396 | * occur, making sure the "free" list remains | ||
| 397 | * sorted. | ||
| 398 | */ | ||
| 399 | old_end = chunk->end; | ||
| 400 | dst = pos; | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /* | ||
| 405 | * Nothing to coalesce. | ||
| 406 | * | ||
| 407 | * Move the entry from the "allocated" list to the "free" | ||
| 408 | * list. | ||
| 409 | */ | ||
| 410 | list_move(&allocated->list, dst); | ||
| 411 | new_chunk_size = handle->end - handle->begin; | ||
| 412 | allocated = NULL; | ||
| 413 | |||
| 414 | exit_memrar_free: | ||
| 415 | |||
| 416 | if (new_chunk_size > allocator->largest_free_area) | ||
| 417 | allocator->largest_free_area = new_chunk_size; | ||
| 418 | |||
| 419 | mutex_unlock(&allocator->lock); | ||
| 420 | |||
| 421 | kfree(allocated); | ||
| 422 | |||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | |||
| 428 | /* | ||
| 429 | Local Variables: | ||
| 430 | c-file-style: "linux" | ||
| 431 | End: | ||
| 432 | */ | ||
diff --git a/drivers/staging/memrar/memrar_allocator.h b/drivers/staging/memrar/memrar_allocator.h deleted file mode 100644 index 0b80dead710f..000000000000 --- a/drivers/staging/memrar/memrar_allocator.h +++ /dev/null | |||
| @@ -1,149 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Intel Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of version 2 of the GNU General | ||
| 6 | * Public License as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be | ||
| 9 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
| 11 | * PURPOSE. See the GNU General Public License for more details. | ||
| 12 | * You should have received a copy of the GNU General Public | ||
| 13 | * License along with this program; if not, write to the Free | ||
| 14 | * Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 15 | * Boston, MA 02111-1307, USA. | ||
| 16 | * The full GNU General Public License is included in this | ||
| 17 | * distribution in the file called COPYING. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef MEMRAR_ALLOCATOR_H | ||
| 21 | #define MEMRAR_ALLOCATOR_H | ||
| 22 | |||
| 23 | |||
| 24 | #include <linux/mutex.h> | ||
| 25 | #include <linux/list.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | |||
| 29 | |||
| 30 | /** | ||
| 31 | * struct memrar_address_range - struct that describes a memory range | ||
| 32 | * @begin: Beginning of available address range. | ||
| 33 | * @end: End of available address range, one past the end, | ||
| 34 | * i.e. [begin, end). | ||
| 35 | */ | ||
| 36 | struct memrar_address_range { | ||
| 37 | /* private: internal use only */ | ||
| 38 | unsigned long begin; | ||
| 39 | unsigned long end; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * struct memrar_address_ranges - list of areas of memory. | ||
| 44 | * @list: Linked list of address ranges. | ||
| 45 | * @range: Memory address range corresponding to given list node. | ||
| 46 | */ | ||
| 47 | struct memrar_address_ranges { | ||
| 48 | /* private: internal use only */ | ||
| 49 | struct list_head list; | ||
| 50 | struct memrar_address_range range; | ||
| 51 | }; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * struct memrar_allocator - encapsulation of the memory allocator state | ||
| 55 | * @lock: Lock used to synchronize access to the memory | ||
| 56 | * allocator state. | ||
| 57 | * @base: Base (start) address of the allocator memory | ||
| 58 | * space. | ||
| 59 | * @capacity: Size of the allocator memory space in bytes. | ||
| 60 | * @block_size: The size in bytes of individual blocks within | ||
| 61 | * the allocator memory space. | ||
| 62 | * @largest_free_area: Largest free area of memory in the allocator | ||
| 63 | * in bytes. | ||
| 64 | * @allocated_list: List of allocated memory block address | ||
| 65 | * ranges. | ||
| 66 | * @free_list: List of free address ranges. | ||
| 67 | * | ||
| 68 | * This structure contains all memory allocator state, including the | ||
| 69 | * base address, capacity, free list, lock, etc. | ||
| 70 | */ | ||
| 71 | struct memrar_allocator { | ||
| 72 | /* private: internal use only */ | ||
| 73 | struct mutex lock; | ||
| 74 | unsigned long base; | ||
| 75 | size_t capacity; | ||
| 76 | size_t block_size; | ||
| 77 | size_t largest_free_area; | ||
| 78 | struct memrar_address_ranges allocated_list; | ||
| 79 | struct memrar_address_ranges free_list; | ||
| 80 | }; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * memrar_create_allocator() - create a memory allocator | ||
| 84 | * @base: Address at which the memory allocator begins. | ||
| 85 | * @capacity: Desired size of the memory allocator. This value must | ||
| 86 | * be larger than the block_size, ideally more than twice | ||
| 87 | * as large since there wouldn't be much point in using a | ||
| 88 | * memory allocator otherwise. | ||
| 89 | * @block_size: The size of individual blocks within the memory | ||
| 90 | * allocator. This value must smaller than the | ||
| 91 | * capacity. | ||
| 92 | * | ||
| 93 | * Create a memory allocator with the given capacity and block size. | ||
| 94 | * The capacity will be reduced to be a multiple of the block size, if | ||
| 95 | * necessary. | ||
| 96 | * | ||
| 97 | * Returns an instance of the memory allocator, if creation succeeds, | ||
| 98 | * otherwise zero if creation fails. Failure may occur if not enough | ||
| 99 | * kernel memory exists to create the memrar_allocator instance | ||
| 100 | * itself, or if the capacity and block_size arguments are not | ||
| 101 | * compatible or make sense. | ||
| 102 | */ | ||
| 103 | struct memrar_allocator *memrar_create_allocator(unsigned long base, | ||
| 104 | size_t capacity, | ||
| 105 | size_t block_size); | ||
| 106 | |||
| 107 | /** | ||
| 108 | * memrar_destroy_allocator() - destroy allocator | ||
| 109 | * @allocator: The allocator being destroyed. | ||
| 110 | * | ||
| 111 | * Reclaim resources held by the memory allocator. The caller must | ||
| 112 | * explicitly free all memory reserved by memrar_allocator_alloc() | ||
| 113 | * prior to calling this function. Otherwise leaks will occur. | ||
| 114 | */ | ||
| 115 | void memrar_destroy_allocator(struct memrar_allocator *allocator); | ||
| 116 | |||
| 117 | /** | ||
| 118 | * memrar_allocator_alloc() - reserve an area of memory of given size | ||
| 119 | * @allocator: The allocator instance being used to reserve buffer. | ||
| 120 | * @size: The size in bytes of the buffer to allocate. | ||
| 121 | * | ||
| 122 | * This functions reserves an area of memory managed by the given | ||
| 123 | * allocator. It returns zero if allocation was not possible. | ||
| 124 | * Failure may occur if the allocator no longer has space available. | ||
| 125 | */ | ||
| 126 | unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator, | ||
| 127 | size_t size); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * memrar_allocator_free() - release buffer starting at given address | ||
| 131 | * @allocator: The allocator instance being used to release the buffer. | ||
| 132 | * @address: The address of the buffer being released. | ||
| 133 | * | ||
| 134 | * Release an area of memory starting at the given address. Failure | ||
| 135 | * could occur if the given address is not in the address space | ||
| 136 | * managed by the allocator. Returns zero on success or an errno | ||
| 137 | * (negative value) on failure. | ||
| 138 | */ | ||
| 139 | long memrar_allocator_free(struct memrar_allocator *allocator, | ||
| 140 | unsigned long address); | ||
| 141 | |||
| 142 | #endif /* MEMRAR_ALLOCATOR_H */ | ||
| 143 | |||
| 144 | |||
| 145 | /* | ||
| 146 | Local Variables: | ||
| 147 | c-file-style: "linux" | ||
| 148 | End: | ||
| 149 | */ | ||
diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c deleted file mode 100644 index cfcaa8e5b8e6..000000000000 --- a/drivers/staging/memrar/memrar_handler.c +++ /dev/null | |||
| @@ -1,1007 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * memrar_handler 1.0: An Intel restricted access region handler device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General | ||
| 8 | * Public License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be | ||
| 11 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
| 13 | * PURPOSE. See the GNU General Public License for more details. | ||
| 14 | * You should have received a copy of the GNU General Public | ||
| 15 | * License along with this program; if not, write to the Free | ||
| 16 | * Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 17 | * Boston, MA 02111-1307, USA. | ||
| 18 | * The full GNU General Public License is included in this | ||
| 19 | * distribution in the file called COPYING. | ||
| 20 | * | ||
| 21 | * ------------------------------------------------------------------- | ||
| 22 | * | ||
| 23 | * Moorestown restricted access regions (RAR) provide isolated | ||
| 24 | * areas of main memory that are only acceessible by authorized | ||
| 25 | * devices. | ||
| 26 | * | ||
| 27 | * The Intel Moorestown RAR handler module exposes a kernel space | ||
| 28 | * RAR memory management mechanism. It is essentially a | ||
| 29 | * RAR-specific allocator. | ||
| 30 | * | ||
| 31 | * Besides providing RAR buffer management, the RAR handler also | ||
| 32 | * behaves in many ways like an OS virtual memory manager. For | ||
| 33 | * example, the RAR "handles" created by the RAR handler are | ||
| 34 | * analogous to user space virtual addresses. | ||
| 35 | * | ||
| 36 | * RAR memory itself is never accessed directly by the RAR | ||
| 37 | * handler. | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <linux/miscdevice.h> | ||
| 41 | #include <linux/fs.h> | ||
| 42 | #include <linux/slab.h> | ||
| 43 | #include <linux/kref.h> | ||
| 44 | #include <linux/mutex.h> | ||
| 45 | #include <linux/kernel.h> | ||
| 46 | #include <linux/uaccess.h> | ||
| 47 | #include <linux/mm.h> | ||
| 48 | #include <linux/ioport.h> | ||
| 49 | #include <linux/io.h> | ||
| 50 | #include <linux/rar_register.h> | ||
| 51 | |||
| 52 | #include "memrar.h" | ||
| 53 | #include "memrar_allocator.h" | ||
| 54 | |||
| 55 | |||
| 56 | #define MEMRAR_VER "1.0" | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Moorestown supports three restricted access regions. | ||
| 60 | * | ||
| 61 | * We only care about the first two, video and audio. The third, | ||
| 62 | * reserved for Chaabi and the P-unit, will be handled by their | ||
| 63 | * respective drivers. | ||
| 64 | */ | ||
| 65 | #define MRST_NUM_RAR 2 | ||
| 66 | |||
| 67 | /* ---------------- -------------------- ------------------- */ | ||
| 68 | |||
| 69 | /** | ||
| 70 | * struct memrar_buffer_info - struct that keeps track of all RAR buffers | ||
| 71 | * @list: Linked list of memrar_buffer_info objects. | ||
| 72 | * @buffer: Core RAR buffer information. | ||
| 73 | * @refcount: Reference count. | ||
| 74 | * @owner: File handle corresponding to process that reserved the | ||
| 75 | * block of memory in RAR. This will be zero for buffers | ||
| 76 | * allocated by other drivers instead of by a user space | ||
| 77 | * process. | ||
| 78 | * | ||
| 79 | * This structure encapsulates a link list of RAR buffers, as well as | ||
| 80 | * other characteristics specific to a given list node, such as the | ||
| 81 | * reference count on the corresponding RAR buffer. | ||
| 82 | */ | ||
| 83 | struct memrar_buffer_info { | ||
| 84 | struct list_head list; | ||
| 85 | struct RAR_buffer buffer; | ||
| 86 | struct kref refcount; | ||
| 87 | struct file *owner; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /** | ||
| 91 | * struct memrar_rar_info - characteristics of a given RAR | ||
| 92 | * @base: Base bus address of the RAR. | ||
| 93 | * @length: Length of the RAR. | ||
| 94 | * @iobase: Virtual address of RAR mapped into kernel. | ||
| 95 | * @allocator: Allocator associated with the RAR. Note the allocator | ||
| 96 | * "capacity" may be smaller than the RAR length if the | ||
| 97 | * length is not a multiple of the configured allocator | ||
| 98 | * block size. | ||
| 99 | * @buffers: Table that keeps track of all reserved RAR buffers. | ||
| 100 | * @lock: Lock used to synchronize access to RAR-specific data | ||
| 101 | * structures. | ||
| 102 | * | ||
| 103 | * Each RAR has an associated memrar_rar_info structure that describes | ||
| 104 | * where in memory the RAR is located, how large it is, and a list of | ||
| 105 | * reserved RAR buffers inside that RAR. Each RAR also has a mutex | ||
| 106 | * associated with it to reduce lock contention when operations on | ||
| 107 | * multiple RARs are performed in parallel. | ||
| 108 | */ | ||
| 109 | struct memrar_rar_info { | ||
| 110 | dma_addr_t base; | ||
| 111 | unsigned long length; | ||
| 112 | void __iomem *iobase; | ||
| 113 | struct memrar_allocator *allocator; | ||
| 114 | struct memrar_buffer_info buffers; | ||
| 115 | struct mutex lock; | ||
| 116 | int allocated; /* True if we own this RAR */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Array of RAR characteristics. | ||
| 121 | */ | ||
| 122 | static struct memrar_rar_info memrars[MRST_NUM_RAR]; | ||
| 123 | |||
| 124 | /* ---------------- -------------------- ------------------- */ | ||
| 125 | |||
| 126 | /* Validate RAR type. */ | ||
| 127 | static inline int memrar_is_valid_rar_type(u32 type) | ||
| 128 | { | ||
| 129 | return type == RAR_TYPE_VIDEO || type == RAR_TYPE_AUDIO; | ||
| 130 | } | ||
| 131 | |||
| 132 | /* Check if an address/handle falls with the given RAR memory range. */ | ||
| 133 | static inline int memrar_handle_in_range(struct memrar_rar_info *rar, | ||
| 134 | u32 vaddr) | ||
| 135 | { | ||
| 136 | unsigned long const iobase = (unsigned long) (rar->iobase); | ||
| 137 | return (vaddr >= iobase && vaddr < iobase + rar->length); | ||
| 138 | } | ||
| 139 | |||
| 140 | /* Retrieve RAR information associated with the given handle. */ | ||
| 141 | static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr) | ||
| 142 | { | ||
| 143 | int i; | ||
| 144 | for (i = 0; i < MRST_NUM_RAR; ++i) { | ||
| 145 | struct memrar_rar_info * const rar = &memrars[i]; | ||
| 146 | if (memrar_handle_in_range(rar, vaddr)) | ||
| 147 | return rar; | ||
| 148 | } | ||
| 149 | |||
| 150 | return NULL; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * memrar_get_bus address - handle to bus address | ||
| 155 | * | ||
| 156 | * Retrieve bus address from given handle. | ||
| 157 | * | ||
| 158 | * Returns address corresponding to given handle. Zero if handle is | ||
| 159 | * invalid. | ||
| 160 | */ | ||
| 161 | static dma_addr_t memrar_get_bus_address( | ||
| 162 | struct memrar_rar_info *rar, | ||
| 163 | u32 vaddr) | ||
| 164 | { | ||
| 165 | unsigned long const iobase = (unsigned long) (rar->iobase); | ||
| 166 | |||
| 167 | if (!memrar_handle_in_range(rar, vaddr)) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | /* | ||
| 171 | * An assumption is made that the virtual address offset is | ||
| 172 | * the same as the bus address offset, at least based on the | ||
| 173 | * way this driver is implemented. For example, vaddr + 2 == | ||
| 174 | * baddr + 2. | ||
| 175 | * | ||
| 176 | * @todo Is that a valid assumption? | ||
| 177 | */ | ||
| 178 | return rar->base + (vaddr - iobase); | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * memrar_get_physical_address - handle to physical address | ||
| 183 | * | ||
| 184 | * Retrieve physical address from given handle. | ||
| 185 | * | ||
| 186 | * Returns address corresponding to given handle. Zero if handle is | ||
| 187 | * invalid. | ||
| 188 | */ | ||
| 189 | static dma_addr_t memrar_get_physical_address( | ||
| 190 | struct memrar_rar_info *rar, | ||
| 191 | u32 vaddr) | ||
| 192 | { | ||
| 193 | /* | ||
| 194 | * @todo This assumes that the bus address and physical | ||
| 195 | * address are the same. That is true for Moorestown | ||
| 196 | * but not necessarily on other platforms. This | ||
| 197 | * deficiency should be addressed at some point. | ||
| 198 | */ | ||
| 199 | return memrar_get_bus_address(rar, vaddr); | ||
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 203 | * memrar_release_block - release a block to the pool | ||
| 204 | * @kref: kref of block | ||
| 205 | * | ||
| 206 | * Core block release code. A node has hit zero references so can | ||
| 207 | * be released and the lists must be updated. | ||
| 208 | * | ||
| 209 | * Note: This code removes the node from a list. Make sure any list | ||
| 210 | * iteration is performed using list_for_each_safe(). | ||
| 211 | */ | ||
| 212 | static void memrar_release_block_i(struct kref *ref) | ||
| 213 | { | ||
| 214 | /* | ||
| 215 | * Last reference is being released. Remove from the table, | ||
| 216 | * and reclaim resources. | ||
| 217 | */ | ||
| 218 | |||
| 219 | struct memrar_buffer_info * const node = | ||
| 220 | container_of(ref, struct memrar_buffer_info, refcount); | ||
| 221 | |||
| 222 | struct RAR_block_info * const user_info = | ||
| 223 | &node->buffer.info; | ||
| 224 | |||
| 225 | struct memrar_allocator * const allocator = | ||
| 226 | memrars[user_info->type].allocator; | ||
| 227 | |||
| 228 | list_del(&node->list); | ||
| 229 | |||
| 230 | memrar_allocator_free(allocator, user_info->handle); | ||
| 231 | |||
| 232 | kfree(node); | ||
| 233 | } | ||
| 234 | |||
| 235 | /** | ||
| 236 | * memrar_init_rar_resources - configure a RAR | ||
| 237 | * @rarnum: rar that has been allocated | ||
| 238 | * @devname: name of our device | ||
| 239 | * | ||
| 240 | * Initialize RAR parameters, such as bus addresses, etc and make | ||
| 241 | * the resource accessible. | ||
| 242 | */ | ||
| 243 | static int memrar_init_rar_resources(int rarnum, char const *devname) | ||
| 244 | { | ||
| 245 | /* ---- Sanity Checks ---- | ||
| 246 | * 1. RAR bus addresses in both Lincroft and Langwell RAR | ||
| 247 | * registers should be the same. | ||
| 248 | * a. There's no way we can do this through IA. | ||
| 249 | * | ||
| 250 | * 2. Secure device ID in Langwell RAR registers should be set | ||
| 251 | * appropriately, e.g. only LPE DMA for the audio RAR, and | ||
| 252 | * security for the other Langwell based RAR registers. | ||
| 253 | * a. There's no way we can do this through IA. | ||
| 254 | * | ||
| 255 | * 3. Audio and video RAR registers and RAR access should be | ||
| 256 | * locked down. If not, enable RAR access control. Except | ||
| 257 | * for debugging purposes, there is no reason for them to | ||
| 258 | * be unlocked. | ||
| 259 | * a. We can only do this for the Lincroft (IA) side. | ||
| 260 | * | ||
| 261 | * @todo Should the RAR handler driver even be aware of audio | ||
| 262 | * and video RAR settings? | ||
| 263 | */ | ||
| 264 | |||
| 265 | /* | ||
| 266 | * RAR buffer block size. | ||
| 267 | * | ||
| 268 | * We choose it to be the size of a page to simplify the | ||
| 269 | * /dev/memrar mmap() implementation and usage. Otherwise | ||
| 270 | * paging is not involved once an RAR is locked down. | ||
| 271 | */ | ||
| 272 | static size_t const RAR_BLOCK_SIZE = PAGE_SIZE; | ||
| 273 | |||
| 274 | dma_addr_t low, high; | ||
| 275 | struct memrar_rar_info * const rar = &memrars[rarnum]; | ||
| 276 | |||
| 277 | BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars)); | ||
| 278 | BUG_ON(!memrar_is_valid_rar_type(rarnum)); | ||
| 279 | BUG_ON(rar->allocated); | ||
| 280 | |||
| 281 | if (rar_get_address(rarnum, &low, &high) != 0) | ||
| 282 | /* No RAR is available. */ | ||
| 283 | return -ENODEV; | ||
| 284 | |||
| 285 | if (low == 0 || high == 0) { | ||
| 286 | rar->base = 0; | ||
| 287 | rar->length = 0; | ||
| 288 | rar->iobase = NULL; | ||
| 289 | rar->allocator = NULL; | ||
| 290 | return -ENOSPC; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* | ||
| 294 | * @todo Verify that LNC and LNW RAR register contents | ||
| 295 | * addresses, security, etc are compatible and | ||
| 296 | * consistent). | ||
| 297 | */ | ||
| 298 | |||
| 299 | rar->length = high - low + 1; | ||
| 300 | |||
| 301 | /* Claim RAR memory as our own. */ | ||
| 302 | if (request_mem_region(low, rar->length, devname) == NULL) { | ||
| 303 | rar->length = 0; | ||
| 304 | pr_err("%s: Unable to claim RAR[%d] memory.\n", | ||
| 305 | devname, rarnum); | ||
| 306 | pr_err("%s: RAR[%d] disabled.\n", devname, rarnum); | ||
| 307 | return -EBUSY; | ||
| 308 | } | ||
| 309 | |||
| 310 | rar->base = low; | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Now map it into the kernel address space. | ||
| 314 | * | ||
| 315 | * Note that the RAR memory may only be accessed by IA | ||
| 316 | * when debugging. Otherwise attempts to access the | ||
| 317 | * RAR memory when it is locked down will result in | ||
| 318 | * behavior similar to writing to /dev/null and | ||
| 319 | * reading from /dev/zero. This behavior is enforced | ||
| 320 | * by the hardware. Even if we don't access the | ||
| 321 | * memory, mapping it into the kernel provides us with | ||
| 322 | * a convenient RAR handle to bus address mapping. | ||
| 323 | */ | ||
| 324 | rar->iobase = ioremap_nocache(rar->base, rar->length); | ||
| 325 | if (rar->iobase == NULL) { | ||
| 326 | pr_err("%s: Unable to map RAR memory.\n", devname); | ||
| 327 | release_mem_region(low, rar->length); | ||
| 328 | return -ENOMEM; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* Initialize corresponding memory allocator. */ | ||
| 332 | rar->allocator = memrar_create_allocator((unsigned long) rar->iobase, | ||
| 333 | rar->length, RAR_BLOCK_SIZE); | ||
| 334 | if (rar->allocator == NULL) { | ||
| 335 | iounmap(rar->iobase); | ||
| 336 | release_mem_region(low, rar->length); | ||
| 337 | return -ENOMEM; | ||
| 338 | } | ||
| 339 | |||
| 340 | pr_info("%s: BRAR[%d] bus address range = [0x%lx, 0x%lx]\n", | ||
| 341 | devname, rarnum, (unsigned long) low, (unsigned long) high); | ||
| 342 | |||
| 343 | pr_info("%s: BRAR[%d] size = %zu KiB\n", | ||
| 344 | devname, rarnum, rar->allocator->capacity / 1024); | ||
| 345 | |||
| 346 | rar->allocated = 1; | ||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | /** | ||
| 351 | * memrar_fini_rar_resources - free up RAR resources | ||
| 352 | * | ||
| 353 | * Finalize RAR resources. Free up the resource tables, hand the memory | ||
| 354 | * back to the kernel, unmap the device and release the address space. | ||
| 355 | */ | ||
| 356 | static void memrar_fini_rar_resources(void) | ||
| 357 | { | ||
| 358 | int z; | ||
| 359 | struct memrar_buffer_info *pos; | ||
| 360 | struct memrar_buffer_info *tmp; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * @todo Do we need to hold a lock at this point in time? | ||
| 364 | * (module initialization failure or exit?) | ||
| 365 | */ | ||
| 366 | |||
| 367 | for (z = MRST_NUM_RAR; z-- != 0; ) { | ||
| 368 | struct memrar_rar_info * const rar = &memrars[z]; | ||
| 369 | |||
| 370 | if (!rar->allocated) | ||
| 371 | continue; | ||
| 372 | |||
| 373 | /* Clean up remaining resources. */ | ||
| 374 | |||
| 375 | list_for_each_entry_safe(pos, | ||
| 376 | tmp, | ||
| 377 | &rar->buffers.list, | ||
| 378 | list) { | ||
| 379 | kref_put(&pos->refcount, memrar_release_block_i); | ||
| 380 | } | ||
| 381 | |||
| 382 | memrar_destroy_allocator(rar->allocator); | ||
| 383 | rar->allocator = NULL; | ||
| 384 | |||
| 385 | iounmap(rar->iobase); | ||
| 386 | release_mem_region(rar->base, rar->length); | ||
| 387 | |||
| 388 | rar->iobase = NULL; | ||
| 389 | rar->base = 0; | ||
| 390 | rar->length = 0; | ||
| 391 | |||
| 392 | unregister_rar(z); | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | /** | ||
| 397 | * memrar_reserve_block - handle an allocation request | ||
| 398 | * @request: block being requested | ||
| 399 | * @filp: owner it is tied to | ||
| 400 | * | ||
| 401 | * Allocate a block of the requested RAR. If successful return the | ||
| 402 | * request object filled in and zero, if not report an error code | ||
| 403 | */ | ||
| 404 | |||
| 405 | static long memrar_reserve_block(struct RAR_buffer *request, | ||
| 406 | struct file *filp) | ||
| 407 | { | ||
| 408 | struct RAR_block_info * const rinfo = &request->info; | ||
| 409 | struct RAR_buffer *buffer; | ||
| 410 | struct memrar_buffer_info *buffer_info; | ||
| 411 | u32 handle; | ||
| 412 | struct memrar_rar_info *rar = NULL; | ||
| 413 | |||
| 414 | /* Prevent array overflow. */ | ||
| 415 | if (!memrar_is_valid_rar_type(rinfo->type)) | ||
| 416 | return -EINVAL; | ||
| 417 | |||
| 418 | rar = &memrars[rinfo->type]; | ||
| 419 | if (!rar->allocated) | ||
| 420 | return -ENODEV; | ||
| 421 | |||
| 422 | /* Reserve memory in RAR. */ | ||
| 423 | handle = memrar_allocator_alloc(rar->allocator, rinfo->size); | ||
| 424 | if (handle == 0) | ||
| 425 | return -ENOMEM; | ||
| 426 | |||
| 427 | buffer_info = kmalloc(sizeof(*buffer_info), GFP_KERNEL); | ||
| 428 | |||
| 429 | if (buffer_info == NULL) { | ||
| 430 | memrar_allocator_free(rar->allocator, handle); | ||
| 431 | return -ENOMEM; | ||
| 432 | } | ||
| 433 | |||
| 434 | buffer = &buffer_info->buffer; | ||
| 435 | buffer->info.type = rinfo->type; | ||
| 436 | buffer->info.size = rinfo->size; | ||
| 437 | |||
| 438 | /* Memory handle corresponding to the bus address. */ | ||
| 439 | buffer->info.handle = handle; | ||
| 440 | buffer->bus_address = memrar_get_bus_address(rar, handle); | ||
| 441 | |||
| 442 | /* | ||
| 443 | * Keep track of owner so that we can later cleanup if | ||
| 444 | * necessary. | ||
| 445 | */ | ||
| 446 | buffer_info->owner = filp; | ||
| 447 | |||
| 448 | kref_init(&buffer_info->refcount); | ||
| 449 | |||
| 450 | mutex_lock(&rar->lock); | ||
| 451 | list_add(&buffer_info->list, &rar->buffers.list); | ||
| 452 | mutex_unlock(&rar->lock); | ||
| 453 | |||
| 454 | rinfo->handle = buffer->info.handle; | ||
| 455 | request->bus_address = buffer->bus_address; | ||
| 456 | |||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | /** | ||
| 461 | * memrar_release_block - release a RAR block | ||
| 462 | * @addr: address in RAR space | ||
| 463 | * | ||
| 464 | * Release a previously allocated block. Releases act on complete | ||
| 465 | * blocks, partially freeing a block is not supported | ||
| 466 | */ | ||
| 467 | |||
| 468 | static long memrar_release_block(u32 addr) | ||
| 469 | { | ||
| 470 | struct memrar_buffer_info *pos; | ||
| 471 | struct memrar_buffer_info *tmp; | ||
| 472 | struct memrar_rar_info * const rar = memrar_get_rar_info(addr); | ||
| 473 | long result = -EINVAL; | ||
| 474 | |||
| 475 | if (rar == NULL) | ||
| 476 | return -ENOENT; | ||
| 477 | |||
| 478 | mutex_lock(&rar->lock); | ||
| 479 | |||
| 480 | /* | ||
| 481 | * Iterate through the buffer list to find the corresponding | ||
| 482 | * buffer to be released. | ||
| 483 | */ | ||
| 484 | list_for_each_entry_safe(pos, | ||
| 485 | tmp, | ||
| 486 | &rar->buffers.list, | ||
| 487 | list) { | ||
| 488 | struct RAR_block_info * const info = | ||
| 489 | &pos->buffer.info; | ||
| 490 | |||
| 491 | /* | ||
| 492 | * Take into account handle offsets that may have been | ||
| 493 | * added to the base handle, such as in the following | ||
| 494 | * scenario: | ||
| 495 | * | ||
| 496 | * u32 handle = base + offset; | ||
| 497 | * rar_handle_to_bus(handle); | ||
| 498 | * rar_release(handle); | ||
| 499 | */ | ||
| 500 | if (addr >= info->handle | ||
| 501 | && addr < (info->handle + info->size) | ||
| 502 | && memrar_is_valid_rar_type(info->type)) { | ||
| 503 | kref_put(&pos->refcount, memrar_release_block_i); | ||
| 504 | result = 0; | ||
| 505 | break; | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | mutex_unlock(&rar->lock); | ||
| 510 | |||
| 511 | return result; | ||
| 512 | } | ||
| 513 | |||
| 514 | /** | ||
| 515 | * memrar_get_stats - read statistics for a RAR | ||
| 516 | * @r: statistics to be filled in | ||
| 517 | * | ||
| 518 | * Returns the statistics data for the RAR, or an error code if | ||
| 519 | * the request cannot be completed | ||
| 520 | */ | ||
| 521 | static long memrar_get_stat(struct RAR_stat *r) | ||
| 522 | { | ||
| 523 | struct memrar_allocator *allocator; | ||
| 524 | |||
| 525 | if (!memrar_is_valid_rar_type(r->type)) | ||
| 526 | return -EINVAL; | ||
| 527 | |||
| 528 | if (!memrars[r->type].allocated) | ||
| 529 | return -ENODEV; | ||
| 530 | |||
| 531 | allocator = memrars[r->type].allocator; | ||
| 532 | |||
| 533 | BUG_ON(allocator == NULL); | ||
| 534 | |||
| 535 | /* | ||
| 536 | * Allocator capacity doesn't change over time. No | ||
| 537 | * need to synchronize. | ||
| 538 | */ | ||
| 539 | r->capacity = allocator->capacity; | ||
| 540 | |||
| 541 | mutex_lock(&allocator->lock); | ||
| 542 | r->largest_block_size = allocator->largest_free_area; | ||
| 543 | mutex_unlock(&allocator->lock); | ||
| 544 | return 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | /** | ||
| 548 | * memrar_ioctl - ioctl callback | ||
| 549 | * @filp: file issuing the request | ||
| 550 | * @cmd: command | ||
| 551 | * @arg: pointer to control information | ||
| 552 | * | ||
| 553 | * Perform one of the ioctls supported by the memrar device | ||
| 554 | */ | ||
| 555 | |||
| 556 | static long memrar_ioctl(struct file *filp, | ||
| 557 | unsigned int cmd, | ||
| 558 | unsigned long arg) | ||
| 559 | { | ||
| 560 | void __user *argp = (void __user *)arg; | ||
| 561 | long result = 0; | ||
| 562 | |||
| 563 | struct RAR_buffer buffer; | ||
| 564 | struct RAR_block_info * const request = &buffer.info; | ||
| 565 | struct RAR_stat rar_info; | ||
| 566 | u32 rar_handle; | ||
| 567 | |||
| 568 | switch (cmd) { | ||
| 569 | case RAR_HANDLER_RESERVE: | ||
| 570 | if (copy_from_user(request, | ||
| 571 | argp, | ||
| 572 | sizeof(*request))) | ||
| 573 | return -EFAULT; | ||
| 574 | |||
| 575 | result = memrar_reserve_block(&buffer, filp); | ||
| 576 | if (result != 0) | ||
| 577 | return result; | ||
| 578 | |||
| 579 | return copy_to_user(argp, request, sizeof(*request)); | ||
| 580 | |||
| 581 | case RAR_HANDLER_RELEASE: | ||
| 582 | if (copy_from_user(&rar_handle, | ||
| 583 | argp, | ||
| 584 | sizeof(rar_handle))) | ||
| 585 | return -EFAULT; | ||
| 586 | |||
| 587 | return memrar_release_block(rar_handle); | ||
| 588 | |||
| 589 | case RAR_HANDLER_STAT: | ||
| 590 | if (copy_from_user(&rar_info, | ||
| 591 | argp, | ||
| 592 | sizeof(rar_info))) | ||
| 593 | return -EFAULT; | ||
| 594 | |||
| 595 | /* | ||
| 596 | * Populate the RAR_stat structure based on the RAR | ||
| 597 | * type given by the user | ||
| 598 | */ | ||
| 599 | if (memrar_get_stat(&rar_info) != 0) | ||
| 600 | return -EINVAL; | ||
| 601 | |||
| 602 | /* | ||
| 603 | * @todo Do we need to verify destination pointer | ||
| 604 | * "argp" is non-zero? Is that already done by | ||
| 605 | * copy_to_user()? | ||
| 606 | */ | ||
| 607 | return copy_to_user(argp, | ||
| 608 | &rar_info, | ||
| 609 | sizeof(rar_info)) ? -EFAULT : 0; | ||
| 610 | |||
| 611 | default: | ||
| 612 | return -ENOTTY; | ||
| 613 | } | ||
| 614 | |||
| 615 | return 0; | ||
| 616 | } | ||
| 617 | |||
| 618 | /** | ||
| 619 | * memrar_mmap - mmap helper for deubgging | ||
| 620 | * @filp: handle doing the mapping | ||
| 621 | * @vma: memory area | ||
| 622 | * | ||
| 623 | * Support the mmap operation on the RAR space for debugging systems | ||
| 624 | * when the memory is not locked down. | ||
| 625 | */ | ||
| 626 | |||
| 627 | static int memrar_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 628 | { | ||
| 629 | /* | ||
| 630 | * This mmap() implementation is predominantly useful for | ||
| 631 | * debugging since the CPU will be prevented from accessing | ||
| 632 | * RAR memory by the hardware when RAR is properly locked | ||
| 633 | * down. | ||
| 634 | * | ||
| 635 | * In order for this implementation to be useful RAR memory | ||
| 636 | * must be not be locked down. However, we only want to do | ||
| 637 | * that when debugging. DO NOT leave RAR memory unlocked in a | ||
| 638 | * deployed device that utilizes RAR. | ||
| 639 | */ | ||
| 640 | |||
| 641 | size_t const size = vma->vm_end - vma->vm_start; | ||
| 642 | |||
| 643 | /* Users pass the RAR handle as the mmap() offset parameter. */ | ||
| 644 | unsigned long const handle = vma->vm_pgoff << PAGE_SHIFT; | ||
| 645 | |||
| 646 | struct memrar_rar_info * const rar = memrar_get_rar_info(handle); | ||
| 647 | unsigned long pfn; | ||
| 648 | |||
| 649 | /* Only allow priviledged apps to go poking around this way */ | ||
| 650 | if (!capable(CAP_SYS_RAWIO)) | ||
| 651 | return -EPERM; | ||
| 652 | |||
| 653 | /* Invalid RAR handle or size passed to mmap(). */ | ||
| 654 | if (rar == NULL | ||
| 655 | || handle == 0 | ||
| 656 | || size > (handle - (unsigned long) rar->iobase)) | ||
| 657 | return -EINVAL; | ||
| 658 | |||
| 659 | /* | ||
| 660 | * Retrieve physical address corresponding to the RAR handle, | ||
| 661 | * and convert it to a page frame. | ||
| 662 | */ | ||
| 663 | pfn = memrar_get_physical_address(rar, handle) >> PAGE_SHIFT; | ||
| 664 | |||
| 665 | |||
| 666 | pr_debug("memrar: mapping RAR range [0x%lx, 0x%lx) into user space.\n", | ||
| 667 | handle, | ||
| 668 | handle + size); | ||
| 669 | |||
| 670 | /* | ||
| 671 | * Map RAR memory into user space. This is really only useful | ||
| 672 | * for debugging purposes since the memory won't be | ||
| 673 | * accessible, i.e. reads return zero and writes are ignored, | ||
| 674 | * when RAR access control is enabled. | ||
| 675 | */ | ||
| 676 | if (remap_pfn_range(vma, | ||
| 677 | vma->vm_start, | ||
| 678 | pfn, | ||
| 679 | size, | ||
| 680 | vma->vm_page_prot)) | ||
| 681 | return -EAGAIN; | ||
| 682 | |||
| 683 | /* vma->vm_ops = &memrar_mem_ops; */ | ||
| 684 | |||
| 685 | return 0; | ||
| 686 | } | ||
| 687 | |||
| 688 | /** | ||
| 689 | * memrar_open - device open method | ||
| 690 | * @inode: inode to open | ||
| 691 | * @filp: file handle | ||
| 692 | * | ||
| 693 | * As we support multiple arbitary opens there is no work to be done | ||
| 694 | * really. | ||
| 695 | */ | ||
| 696 | |||
| 697 | static int memrar_open(struct inode *inode, struct file *filp) | ||
| 698 | { | ||
| 699 | nonseekable_open(inode, filp); | ||
| 700 | return 0; | ||
| 701 | } | ||
| 702 | |||
| 703 | /** | ||
| 704 | * memrar_release - close method for miscev | ||
| 705 | * @inode: inode of device | ||
| 706 | * @filp: handle that is going away | ||
| 707 | * | ||
| 708 | * Free up all the regions that belong to this file handle. We use | ||
| 709 | * the handle as a natural Linux style 'lifetime' indicator and to | ||
| 710 | * ensure resources are not leaked when their owner explodes in an | ||
| 711 | * unplanned fashion. | ||
| 712 | */ | ||
| 713 | |||
| 714 | static int memrar_release(struct inode *inode, struct file *filp) | ||
| 715 | { | ||
| 716 | /* Free all regions associated with the given file handle. */ | ||
| 717 | |||
| 718 | struct memrar_buffer_info *pos; | ||
| 719 | struct memrar_buffer_info *tmp; | ||
| 720 | int z; | ||
| 721 | |||
| 722 | for (z = 0; z != MRST_NUM_RAR; ++z) { | ||
| 723 | struct memrar_rar_info * const rar = &memrars[z]; | ||
| 724 | |||
| 725 | mutex_lock(&rar->lock); | ||
| 726 | |||
| 727 | list_for_each_entry_safe(pos, | ||
| 728 | tmp, | ||
| 729 | &rar->buffers.list, | ||
| 730 | list) { | ||
| 731 | if (filp == pos->owner) | ||
| 732 | kref_put(&pos->refcount, | ||
| 733 | memrar_release_block_i); | ||
| 734 | } | ||
| 735 | |||
| 736 | mutex_unlock(&rar->lock); | ||
| 737 | } | ||
| 738 | |||
| 739 | return 0; | ||
| 740 | } | ||
| 741 | |||
| 742 | /** | ||
| 743 | * rar_reserve - reserve RAR memory | ||
| 744 | * @buffers: buffers to reserve | ||
| 745 | * @count: number wanted | ||
| 746 | * | ||
| 747 | * Reserve a series of buffers in the RAR space. Returns the number of | ||
| 748 | * buffers successfully allocated | ||
| 749 | */ | ||
| 750 | |||
| 751 | size_t rar_reserve(struct RAR_buffer *buffers, size_t count) | ||
| 752 | { | ||
| 753 | struct RAR_buffer * const end = | ||
| 754 | (buffers == NULL ? buffers : buffers + count); | ||
| 755 | struct RAR_buffer *i; | ||
| 756 | |||
| 757 | size_t reserve_count = 0; | ||
| 758 | |||
| 759 | for (i = buffers; i != end; ++i) { | ||
| 760 | if (memrar_reserve_block(i, NULL) == 0) | ||
| 761 | ++reserve_count; | ||
| 762 | else | ||
| 763 | i->bus_address = 0; | ||
| 764 | } | ||
| 765 | |||
| 766 | return reserve_count; | ||
| 767 | } | ||
| 768 | EXPORT_SYMBOL(rar_reserve); | ||
| 769 | |||
| 770 | /** | ||
| 771 | * rar_release - return RAR buffers | ||
| 772 | * @buffers: buffers to release | ||
| 773 | * @size: size of released block | ||
| 774 | * | ||
| 775 | * Return a set of buffers to the RAR pool | ||
| 776 | */ | ||
| 777 | |||
| 778 | size_t rar_release(struct RAR_buffer *buffers, size_t count) | ||
| 779 | { | ||
| 780 | struct RAR_buffer * const end = | ||
| 781 | (buffers == NULL ? buffers : buffers + count); | ||
| 782 | struct RAR_buffer *i; | ||
| 783 | |||
| 784 | size_t release_count = 0; | ||
| 785 | |||
| 786 | for (i = buffers; i != end; ++i) { | ||
| 787 | u32 * const handle = &i->info.handle; | ||
| 788 | if (memrar_release_block(*handle) == 0) { | ||
| 789 | /* | ||
| 790 | * @todo We assume we should do this each time | ||
| 791 | * the ref count is decremented. Should | ||
| 792 | * we instead only do this when the ref | ||
| 793 | * count has dropped to zero, and the | ||
| 794 | * buffer has been completely | ||
| 795 | * released/unmapped? | ||
| 796 | */ | ||
| 797 | *handle = 0; | ||
| 798 | ++release_count; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | return release_count; | ||
| 803 | } | ||
| 804 | EXPORT_SYMBOL(rar_release); | ||
| 805 | |||
| 806 | /** | ||
| 807 | * rar_handle_to_bus - RAR to bus address | ||
| 808 | * @buffers: RAR buffer structure | ||
| 809 | * @count: number of buffers to convert | ||
| 810 | * | ||
| 811 | * Turn a list of RAR handle mappings into actual bus addresses. Note | ||
| 812 | * that when the device is locked down the bus addresses in question | ||
| 813 | * are not CPU accessible. | ||
| 814 | */ | ||
| 815 | |||
| 816 | size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count) | ||
| 817 | { | ||
| 818 | struct RAR_buffer * const end = | ||
| 819 | (buffers == NULL ? buffers : buffers + count); | ||
| 820 | struct RAR_buffer *i; | ||
| 821 | struct memrar_buffer_info *pos; | ||
| 822 | |||
| 823 | size_t conversion_count = 0; | ||
| 824 | |||
| 825 | /* | ||
| 826 | * Find all bus addresses corresponding to the given handles. | ||
| 827 | * | ||
| 828 | * @todo Not liking this nested loop. Optimize. | ||
| 829 | */ | ||
| 830 | for (i = buffers; i != end; ++i) { | ||
| 831 | struct memrar_rar_info * const rar = | ||
| 832 | memrar_get_rar_info(i->info.handle); | ||
| 833 | |||
| 834 | /* | ||
| 835 | * Check if we have a bogus handle, and then continue | ||
| 836 | * with remaining buffers. | ||
| 837 | */ | ||
| 838 | if (rar == NULL) { | ||
| 839 | i->bus_address = 0; | ||
| 840 | continue; | ||
| 841 | } | ||
| 842 | |||
| 843 | mutex_lock(&rar->lock); | ||
| 844 | |||
| 845 | list_for_each_entry(pos, &rar->buffers.list, list) { | ||
| 846 | struct RAR_block_info * const user_info = | ||
| 847 | &pos->buffer.info; | ||
| 848 | |||
| 849 | /* | ||
| 850 | * Take into account handle offsets that may | ||
| 851 | * have been added to the base handle, such as | ||
| 852 | * in the following scenario: | ||
| 853 | * | ||
| 854 | * u32 handle = base + offset; | ||
| 855 | * rar_handle_to_bus(handle); | ||
| 856 | */ | ||
| 857 | |||
| 858 | if (i->info.handle >= user_info->handle | ||
| 859 | && i->info.handle < (user_info->handle | ||
| 860 | + user_info->size)) { | ||
| 861 | u32 const offset = | ||
| 862 | i->info.handle - user_info->handle; | ||
| 863 | |||
| 864 | i->info.type = user_info->type; | ||
| 865 | i->info.size = user_info->size - offset; | ||
| 866 | i->bus_address = | ||
| 867 | pos->buffer.bus_address | ||
| 868 | + offset; | ||
| 869 | |||
| 870 | /* Increment the reference count. */ | ||
| 871 | kref_get(&pos->refcount); | ||
| 872 | |||
| 873 | ++conversion_count; | ||
| 874 | break; | ||
| 875 | } else { | ||
| 876 | i->bus_address = 0; | ||
| 877 | } | ||
| 878 | } | ||
| 879 | |||
| 880 | mutex_unlock(&rar->lock); | ||
| 881 | } | ||
| 882 | |||
| 883 | return conversion_count; | ||
| 884 | } | ||
| 885 | EXPORT_SYMBOL(rar_handle_to_bus); | ||
| 886 | |||
| 887 | static const struct file_operations memrar_fops = { | ||
| 888 | .owner = THIS_MODULE, | ||
| 889 | .unlocked_ioctl = memrar_ioctl, | ||
| 890 | .mmap = memrar_mmap, | ||
| 891 | .open = memrar_open, | ||
| 892 | .release = memrar_release, | ||
| 893 | .llseek = no_llseek, | ||
| 894 | }; | ||
| 895 | |||
| 896 | static struct miscdevice memrar_miscdev = { | ||
| 897 | .minor = MISC_DYNAMIC_MINOR, /* dynamic allocation */ | ||
| 898 | .name = "memrar", /* /dev/memrar */ | ||
| 899 | .fops = &memrar_fops | ||
| 900 | }; | ||
| 901 | |||
| 902 | static char const banner[] __initdata = | ||
| 903 | KERN_INFO | ||
| 904 | "Intel RAR Handler: " MEMRAR_VER " initialized.\n"; | ||
| 905 | |||
| 906 | /** | ||
| 907 | * memrar_registration_callback - RAR obtained | ||
| 908 | * @rar: RAR number | ||
| 909 | * | ||
| 910 | * We have been granted ownership of the RAR. Add it to our memory | ||
| 911 | * management tables | ||
| 912 | */ | ||
| 913 | |||
| 914 | static int memrar_registration_callback(unsigned long rar) | ||
| 915 | { | ||
| 916 | /* | ||
| 917 | * We initialize the RAR parameters early on so that we can | ||
| 918 | * discontinue memrar device initialization and registration | ||
| 919 | * if suitably configured RARs are not available. | ||
| 920 | */ | ||
| 921 | return memrar_init_rar_resources(rar, memrar_miscdev.name); | ||
| 922 | } | ||
| 923 | |||
| 924 | /** | ||
| 925 | * memrar_init - initialise RAR support | ||
| 926 | * | ||
| 927 | * Initialise support for RAR handlers. This may get loaded before | ||
| 928 | * the RAR support is activated, but the callbacks on the registration | ||
| 929 | * will handle that situation for us anyway. | ||
| 930 | */ | ||
| 931 | |||
| 932 | static int __init memrar_init(void) | ||
| 933 | { | ||
| 934 | int err; | ||
| 935 | int i; | ||
| 936 | |||
| 937 | printk(banner); | ||
| 938 | |||
| 939 | /* | ||
| 940 | * Some delayed initialization is performed in this driver. | ||
| 941 | * Make sure resources that are used during driver clean-up | ||
| 942 | * (e.g. during driver's release() function) are fully | ||
| 943 | * initialized before first use. This is particularly | ||
| 944 | * important for the case when the delayed initialization | ||
| 945 | * isn't completed, leaving behind a partially initialized | ||
| 946 | * driver. | ||
| 947 | * | ||
| 948 | * Such a scenario can occur when RAR is not available on the | ||
| 949 | * platform, and the driver is release()d. | ||
| 950 | */ | ||
| 951 | for (i = 0; i != ARRAY_SIZE(memrars); ++i) { | ||
| 952 | struct memrar_rar_info * const rar = &memrars[i]; | ||
| 953 | mutex_init(&rar->lock); | ||
| 954 | INIT_LIST_HEAD(&rar->buffers.list); | ||
| 955 | } | ||
| 956 | |||
| 957 | err = misc_register(&memrar_miscdev); | ||
| 958 | if (err) | ||
| 959 | return err; | ||
| 960 | |||
| 961 | /* Now claim the two RARs we want */ | ||
| 962 | err = register_rar(0, memrar_registration_callback, 0); | ||
| 963 | if (err) | ||
| 964 | goto fail; | ||
| 965 | |||
| 966 | err = register_rar(1, memrar_registration_callback, 1); | ||
| 967 | if (err == 0) | ||
| 968 | return 0; | ||
| 969 | |||
| 970 | /* It is possible rar 0 registered and allocated resources then rar 1 | ||
| 971 | failed so do a full resource free */ | ||
| 972 | memrar_fini_rar_resources(); | ||
| 973 | fail: | ||
| 974 | misc_deregister(&memrar_miscdev); | ||
| 975 | return err; | ||
| 976 | } | ||
| 977 | |||
| 978 | /** | ||
| 979 | * memrar_exit - unregister and unload | ||
| 980 | * | ||
| 981 | * Unregister the device and then unload any mappings and release | ||
| 982 | * the RAR resources | ||
| 983 | */ | ||
| 984 | |||
| 985 | static void __exit memrar_exit(void) | ||
| 986 | { | ||
| 987 | misc_deregister(&memrar_miscdev); | ||
| 988 | memrar_fini_rar_resources(); | ||
| 989 | } | ||
| 990 | |||
| 991 | |||
| 992 | module_init(memrar_init); | ||
| 993 | module_exit(memrar_exit); | ||
| 994 | |||
| 995 | |||
| 996 | MODULE_AUTHOR("Ossama Othman <ossama.othman@intel.com>"); | ||
| 997 | MODULE_DESCRIPTION("Intel Restricted Access Region Handler"); | ||
| 998 | MODULE_LICENSE("GPL"); | ||
| 999 | MODULE_VERSION(MEMRAR_VER); | ||
| 1000 | |||
| 1001 | |||
| 1002 | |||
| 1003 | /* | ||
| 1004 | Local Variables: | ||
| 1005 | c-file-style: "linux" | ||
| 1006 | End: | ||
| 1007 | */ | ||
