Skip to content

Commit dacf8e4

Browse files
authored
Added UIO kernel modules to map shared NVMe memory
`uio_memmap` uses a device tree binding to load the driver, and is preferred. `uio_memmap_platform` creates a static platform device to load the driver.
1 parent d48fd81 commit dacf8e4

File tree

4 files changed

+316
-0
lines changed

4 files changed

+316
-0
lines changed

uio_memmap/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
obj-m += uio_memmap.o
2+
#uio_memmap-objs += uio_memmap.o
3+
4+
all:
5+
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
6+
clean:
7+
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

uio_memmap/uio_memmap.c

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#include <linux/device.h>
2+
#include <linux/module.h>
3+
#include <linux/slab.h>
4+
#include <linux/uio_driver.h>
5+
#include <linux/platform_device.h>
6+
#include <linux/dma-mapping.h>
7+
#include <linux/of_reserved_mem.h>
8+
#include <linux/pm_runtime.h>
9+
10+
#include <linux/of.h>
11+
#include <linux/of_platform.h>
12+
#include <linux/of_address.h>
13+
14+
15+
#define DYNAMIC_MAP_SIZE 0x40000000
16+
17+
18+
struct uio_memmap_platdata {
19+
struct uio_info *uioinfo;
20+
struct platform_device *pdev;
21+
bool open;
22+
};
23+
24+
25+
static int uio_memmap_open(struct uio_info *info, struct inode *inode)
26+
{
27+
int ret = 0;
28+
struct uio_memmap_platdata *priv = info->priv;
29+
struct platform_device *pdev = priv->pdev;
30+
void *mem = NULL;
31+
dma_addr_t mem_phys = 0x40000000;
32+
33+
if (priv->open) {
34+
dev_err(&pdev->dev, "Device is already open\n");
35+
return -EBUSY;
36+
}
37+
38+
mem = dma_zalloc_coherent(&pdev->dev, DYNAMIC_MAP_SIZE, &mem_phys, GFP_KERNEL);
39+
if (!mem) {
40+
dev_err(&pdev->dev, "Failed to allocate mem memory\n");
41+
return -ENOMEM;
42+
}
43+
dev_info(&pdev->dev, "uio_memmap_open - Allocated DMA mem:\n VIRT: 0x%016llx\n PHYS: 0x%016llx\n", (u64)mem, mem_phys);
44+
45+
info->mem[0].addr = mem_phys;
46+
info->mem[0].internal_addr = mem;
47+
48+
priv->open = true;
49+
50+
return ret;
51+
}
52+
53+
static int uio_memmap_release(struct uio_info *info, struct inode *inode)
54+
{
55+
struct uio_memmap_platdata *priv = info->priv;
56+
struct platform_device *pdev = priv->pdev;
57+
58+
dma_free_coherent(&pdev->dev, DYNAMIC_MAP_SIZE, info->mem[0].internal_addr, info->mem[0].addr);
59+
60+
info->mem[0].addr = 0;
61+
info->mem[0].internal_addr = 0;
62+
63+
priv->open = false;
64+
65+
dev_info(&pdev->dev, "uio_memmap_release - Freed DMA mem\n");
66+
67+
return 0;
68+
}
69+
70+
static int uio_memmap_probe(struct platform_device *pdev)
71+
{
72+
struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
73+
struct uio_memmap_platdata *priv;
74+
int ret = -EINVAL;
75+
// void *mem = NULL;
76+
// dma_addr_t mem_phys;
77+
int err;
78+
79+
dev_info(&pdev->dev, "probe start\n");
80+
81+
if (!pdev->dev.of_node) {
82+
dev_err(&pdev->dev, "No device tree node\n");
83+
ret = -ENODEV;
84+
goto error0;
85+
}
86+
87+
uioinfo = devm_kzalloc(&pdev->dev, sizeof(*uioinfo), GFP_KERNEL);
88+
if (!uioinfo) {
89+
dev_err(&pdev->dev, "Failed to allocate uio_info memory\n");
90+
ret = -ENOMEM;
91+
goto error0;
92+
}
93+
94+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
95+
if (!priv) {
96+
dev_err(&pdev->dev, "unable to kmalloc\n");
97+
ret = -ENOMEM;
98+
goto error0;
99+
}
100+
101+
priv->uioinfo = uioinfo;
102+
priv->pdev = pdev;
103+
priv->open = false;
104+
uioinfo->priv = priv;
105+
106+
/* Initialize reserved memory resources */
107+
err = of_reserved_mem_device_init(&pdev->dev);
108+
if (err) {
109+
dev_err(&pdev->dev, "Could not get reserved memory: %d\n", err);
110+
ret = -ENOMEM;
111+
goto error0;
112+
}
113+
114+
/* Allocate memory */
115+
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
116+
if (err) {
117+
dev_err(&pdev->dev, "Could not set coherent mask: %d\n", err);
118+
ret = -ENOMEM;
119+
goto error1;
120+
}
121+
122+
// mem = dma_alloc_coherent(&pdev->dev, DYNAMIC_MAP_SIZE, &mem_phys, GFP_KERNEL);
123+
// if (!mem) {
124+
// dev_err(&pdev->dev, "Failed to allocate mem memory\n");
125+
// ret = -ENOMEM;
126+
// goto error1;
127+
// }
128+
// dev_info(&pdev->dev, "Allocated mem:\nVIRT: 0x%016llx\nPHYS: 0x%016llx\n", (u64)mem, mem_phys);
129+
130+
uioinfo->name = "memmap";
131+
uioinfo->version = "0.1";
132+
uioinfo->irq = UIO_IRQ_NONE;
133+
uioinfo->open = uio_memmap_open;
134+
uioinfo->release = uio_memmap_release;
135+
136+
// uioinfo->mem[0].name = "mem0";
137+
// uioinfo->mem[0].addr = mem_phys;
138+
// uioinfo->mem[0].internal_addr = mem;
139+
// uioinfo->mem[0].size = DYNAMIC_MAP_SIZE;
140+
// uioinfo->mem[0].memtype = UIO_MEM_PHYS;
141+
142+
uioinfo->mem[0].name = "mem0";
143+
uioinfo->mem[0].addr = 0;
144+
uioinfo->mem[0].internal_addr = 0;
145+
uioinfo->mem[0].size = DYNAMIC_MAP_SIZE;
146+
uioinfo->mem[0].memtype = UIO_MEM_PHYS;
147+
148+
// pm_runtime_enable(&pdev->dev);
149+
150+
ret = uio_register_device(&pdev->dev, priv->uioinfo);
151+
if (ret) {
152+
dev_err(&pdev->dev, "Failed to register UIO device\n");
153+
// pm_runtime_disable(&pdev->dev);
154+
goto error2;
155+
}
156+
157+
platform_set_drvdata(pdev, priv);
158+
159+
dev_info(&pdev->dev, "probe successful\n");
160+
161+
return 0;
162+
163+
error2:
164+
// dma_free_coherent(&pdev->dev, DYNAMIC_MAP_SIZE, mem, mem_phys);
165+
error1:
166+
of_reserved_mem_device_release(&pdev->dev);
167+
error0:
168+
return ret;
169+
}
170+
171+
static int uio_memmap_remove(struct platform_device *pdev)
172+
{
173+
struct uio_memmap_platdata *priv = platform_get_drvdata(pdev);
174+
175+
uio_unregister_device(priv->uioinfo);
176+
// pm_runtime_disable(&pdev->dev);
177+
// dma_free_coherent(&pdev->dev, DYNAMIC_MAP_SIZE, priv->uioinfo->mem[0].internal_addr, priv->uioinfo->mem[0].addr);
178+
of_reserved_mem_device_release(&pdev->dev);
179+
180+
dev_info(&pdev->dev, "removed\n");
181+
return 0;
182+
}
183+
184+
185+
//static int uio_memmap_runtime_nop(struct device *dev)
186+
//{
187+
// return 0;
188+
//}
189+
190+
//static const struct dev_pm_ops uio_memmap_dev_pm_ops = {
191+
// .runtime_suspend = uio_memmap_runtime_nop,
192+
// .runtime_resume = uio_memmap_runtime_nop,
193+
//};
194+
195+
static const struct of_device_id uio_memmap_of_match[] = {
196+
{ .compatible = "rj,uio-memmap", },
197+
// { .compatible = "rj,uio-memtest", },
198+
{ /* end of list */ },
199+
};
200+
MODULE_DEVICE_TABLE(of, uio_memmap_of_match);
201+
202+
static struct platform_driver uio_memmap_driver = {
203+
.probe = uio_memmap_probe,
204+
.remove = uio_memmap_remove,
205+
.driver = {
206+
.name = "uio-memmap",
207+
.of_match_table = uio_memmap_of_match,
208+
// .pm = &uio_memmap_dev_pm_ops,
209+
},
210+
};
211+
module_platform_driver(uio_memmap_driver);
212+
213+
214+
MODULE_LICENSE("GPL");
215+
MODULE_AUTHOR("Russell Joyce");
216+
MODULE_DESCRIPTION("UIO-based Memory Test");
217+
MODULE_VERSION("0.1");

uio_memmap_platform/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
obj-m += uio_memmap.o
2+
#uio_memmap-objs += uio_memmap.o
3+
4+
all:
5+
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
6+
clean:
7+
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

uio_memmap_platform/uio_memmap.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include <linux/device.h>
2+
#include <linux/module.h>
3+
#include <linux/slab.h>
4+
#include <linux/uio_driver.h>
5+
#include <linux/platform_device.h>
6+
7+
8+
static struct platform_device *pdev = NULL;
9+
static struct uio_info *info = NULL;
10+
static void *mem = NULL;
11+
12+
13+
static int __init memmap_init(void)
14+
{
15+
phys_addr_t mem_phys;
16+
17+
pr_info("uio_memmap: init start\n");
18+
19+
pdev = platform_device_register_simple("uio_memmap", 0, NULL, 0);
20+
if (IS_ERR(pdev)) {
21+
pr_err("Failed to register platform device\n");
22+
return PTR_ERR(pdev);
23+
}
24+
25+
info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
26+
if (!info) {
27+
pr_err("Failed to allocate uio_info memory\n");
28+
return -ENOMEM;
29+
}
30+
31+
mem = kzalloc(0x100000, GFP_KERNEL);
32+
if (!mem) {
33+
pr_err("Failed to allocate mem memory\n");
34+
goto free_info;
35+
}
36+
37+
mem_phys = virt_to_phys(mem);
38+
39+
pr_info("uio_memmap: Allocated memory:\nVIRT: 0x%016llx\nPHYS: 0x%016llx\n", (phys_addr_t)mem, mem_phys);
40+
41+
info->name = "memmap";
42+
info->version = "0.1";
43+
44+
info->irq = UIO_IRQ_NONE;
45+
46+
info->mem[0].name = "mem0";
47+
info->mem[0].addr = mem_phys;
48+
info->mem[0].internal_addr = mem;
49+
info->mem[0].size = 0x100000;
50+
info->mem[0].memtype = UIO_MEM_PHYS;
51+
52+
if (uio_register_device(&pdev->dev, info)) {
53+
pr_err("Failed to register UIO device\n");
54+
goto free_mem;
55+
}
56+
57+
pr_info("uio_memmap: init done\n");
58+
59+
return 0;
60+
61+
free_mem:
62+
kfree(mem);
63+
free_info:
64+
kfree(info);
65+
return -ENODEV;
66+
}
67+
68+
static void __exit memmap_exit(void)
69+
{
70+
uio_unregister_device(info);
71+
kfree(info);
72+
kfree(mem);
73+
platform_device_unregister(pdev);
74+
75+
pr_info("uio_memmap: exited\n");
76+
}
77+
78+
79+
module_init(memmap_init);
80+
module_exit(memmap_exit);
81+
82+
MODULE_LICENSE("GPL");
83+
MODULE_AUTHOR("Russell Joyce");
84+
MODULE_DESCRIPTION("UIO-based Memory Mapping");
85+
MODULE_VERSION("0.1");

0 commit comments

Comments
 (0)