4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
45 #include <sys/rwlock.h>
46 #include <sys/systm.h>
47 #include <sys/sysctl.h>
49 #include <machine/bus.h>
53 #include <vm/vm_object.h>
54 #include <vm/vm_page.h>
55 #include <vm/vm_pager.h>
57 static int contigmem_load(void);
58 static int contigmem_unload(void);
59 static int contigmem_physaddr(SYSCTL_HANDLER_ARGS
);
61 static d_mmap_t contigmem_mmap
;
62 static d_mmap_single_t contigmem_mmap_single
;
63 static d_open_t contigmem_open
;
65 static int contigmem_num_buffers
= RTE_CONTIGMEM_DEFAULT_NUM_BUFS
;
66 static int64_t contigmem_buffer_size
= RTE_CONTIGMEM_DEFAULT_BUF_SIZE
;
68 static eventhandler_tag contigmem_eh_tag
;
69 static void *contigmem_buffers
[RTE_CONTIGMEM_MAX_NUM_BUFS
];
70 static struct cdev
*contigmem_cdev
= NULL
;
72 TUNABLE_INT("hw.contigmem.num_buffers", &contigmem_num_buffers
);
73 TUNABLE_QUAD("hw.contigmem.buffer_size", &contigmem_buffer_size
);
75 static SYSCTL_NODE(_hw
, OID_AUTO
, contigmem
, CTLFLAG_RD
, 0, "contigmem");
77 SYSCTL_INT(_hw_contigmem
, OID_AUTO
, num_buffers
, CTLFLAG_RD
,
78 &contigmem_num_buffers
, 0, "Number of contigmem buffers allocated");
79 SYSCTL_QUAD(_hw_contigmem
, OID_AUTO
, buffer_size
, CTLFLAG_RD
,
80 &contigmem_buffer_size
, 0, "Size of each contiguous buffer");
82 static SYSCTL_NODE(_hw_contigmem
, OID_AUTO
, physaddr
, CTLFLAG_RD
, 0,
85 MALLOC_DEFINE(M_CONTIGMEM
, "contigmem", "contigmem(4) allocations");
87 static int contigmem_modevent(module_t mod
, int type
, void *arg
)
93 error
= contigmem_load();
96 error
= contigmem_unload();
105 moduledata_t contigmem_mod
= {
107 (modeventhand_t
)contigmem_modevent
,
111 DECLARE_MODULE(contigmem
, contigmem_mod
, SI_SUB_DRIVERS
, SI_ORDER_ANY
);
112 MODULE_VERSION(contigmem
, 1);
114 static struct cdevsw contigmem_ops
= {
115 .d_name
= "contigmem",
116 .d_version
= D_VERSION
,
117 .d_mmap
= contigmem_mmap
,
118 .d_mmap_single
= contigmem_mmap_single
,
119 .d_open
= contigmem_open
,
125 char index_string
[8], description
[32];
128 if (contigmem_num_buffers
> RTE_CONTIGMEM_MAX_NUM_BUFS
) {
129 printf("%d buffers requested is greater than %d allowed\n",
130 contigmem_num_buffers
, RTE_CONTIGMEM_MAX_NUM_BUFS
);
134 if (contigmem_buffer_size
< PAGE_SIZE
||
135 (contigmem_buffer_size
& (contigmem_buffer_size
- 1)) != 0) {
136 printf("buffer size 0x%lx is not greater than PAGE_SIZE and "
137 "power of two\n", contigmem_buffer_size
);
141 for (i
= 0; i
< contigmem_num_buffers
; i
++) {
142 contigmem_buffers
[i
] =
143 contigmalloc(contigmem_buffer_size
, M_CONTIGMEM
, M_ZERO
, 0,
144 BUS_SPACE_MAXADDR
, contigmem_buffer_size
, 0);
146 if (contigmem_buffers
[i
] == NULL
) {
147 printf("contigmalloc failed for buffer %d\n", i
);
151 printf("%2u: virt=%p phys=%p\n", i
, contigmem_buffers
[i
],
152 (void *)pmap_kextract((vm_offset_t
)contigmem_buffers
[i
]));
154 snprintf(index_string
, sizeof(index_string
), "%d", i
);
155 snprintf(description
, sizeof(description
),
156 "phys addr for buffer %d", i
);
157 SYSCTL_ADD_PROC(NULL
,
158 &SYSCTL_NODE_CHILDREN(_hw_contigmem
, physaddr
), OID_AUTO
,
159 index_string
, CTLTYPE_U64
| CTLFLAG_RD
,
160 (void *)(uintptr_t)i
, 0, contigmem_physaddr
, "LU",
164 contigmem_cdev
= make_dev_credf(0, &contigmem_ops
, 0, NULL
, UID_ROOT
,
165 GID_WHEEL
, 0600, "contigmem");
175 if (contigmem_cdev
!= NULL
)
176 destroy_dev(contigmem_cdev
);
178 if (contigmem_eh_tag
!= NULL
)
179 EVENTHANDLER_DEREGISTER(process_exit
, contigmem_eh_tag
);
181 for (i
= 0; i
< RTE_CONTIGMEM_MAX_NUM_BUFS
; i
++)
182 if (contigmem_buffers
[i
] != NULL
)
183 contigfree(contigmem_buffers
[i
], contigmem_buffer_size
,
190 contigmem_physaddr(SYSCTL_HANDLER_ARGS
)
193 int index
= (int)(uintptr_t)arg1
;
195 physaddr
= (uint64_t)vtophys(contigmem_buffers
[index
]);
196 return sysctl_handle_64(oidp
, &physaddr
, 0, req
);
200 contigmem_open(struct cdev
*cdev
, int fflags
, int devtype
,
207 contigmem_mmap(struct cdev
*cdev
, vm_ooffset_t offset
, vm_paddr_t
*paddr
,
208 int prot
, vm_memattr_t
*memattr
)
216 contigmem_mmap_single(struct cdev
*cdev
, vm_ooffset_t
*offset
, vm_size_t size
,
217 struct vm_object
**obj
, int nprot
)
219 uint64_t buffer_index
;
222 * The buffer index is encoded in the offset. Divide the offset by
223 * PAGE_SIZE to get the index of the buffer requested by the user
226 buffer_index
= *offset
/ PAGE_SIZE
;
227 if (buffer_index
>= contigmem_num_buffers
)
230 memset(contigmem_buffers
[buffer_index
], 0, contigmem_buffer_size
);
231 *offset
= (vm_ooffset_t
)vtophys(contigmem_buffers
[buffer_index
]);
232 *obj
= vm_pager_allocate(OBJT_DEVICE
, cdev
, size
, nprot
, *offset
,
233 curthread
->td_ucred
);