xref: /haiku/src/add-ons/kernel/drivers/disk/nvme/compat/libnvme_haiku.cpp (revision 5c1f231967bbf06af56728b86ad70f266c99f64d)
1 /*
2  * Copyright 2019-2022, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Augustin Cavalier <waddlesplash>
7  */
8 
9 #include <debug.h>
10 #include <kernel/vm/vm.h>
11 #include <PCI.h>
12 
13 extern "C" {
14 #include "nvme.h"
15 #include "nvme_log.h"
16 #include "nvme_mem.h"
17 #include "nvme_pci.h"
18 }
19 
20 
21 static pci_module_info* sPCIModule = NULL;
22 
23 
24 // #pragma mark - memory
25 
26 
27 int
nvme_mem_init()28 nvme_mem_init()
29 {
30 	/* nothing to do */
31 	return 0;
32 }
33 
34 
35 void
nvme_mem_cleanup()36 nvme_mem_cleanup()
37 {
38 	/* nothing to do */
39 }
40 
41 
42 void*
nvme_mem_alloc_node(size_t size,size_t align,unsigned int node_id,phys_addr_t * paddr)43 nvme_mem_alloc_node(size_t size, size_t align, unsigned int node_id,
44 	phys_addr_t* paddr)
45 {
46 	size = ROUNDUP(size, B_PAGE_SIZE);
47 
48 	virtual_address_restrictions virtualRestrictions = {};
49 
50 	physical_address_restrictions physicalRestrictions = {};
51 	physicalRestrictions.alignment = align;
52 
53 	void* address;
54 	area_id area = create_area_etc(B_SYSTEM_TEAM, "nvme physical buffer",
55 		size, B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
56 		0, 0, &virtualRestrictions, &physicalRestrictions, &address);
57 	if (area < 0)
58 		return NULL;
59 
60 	if (paddr != NULL)
61 		*paddr = nvme_mem_vtophys(address);
62 	return address;
63 }
64 
65 
66 void*
nvme_malloc_node(size_t size,size_t align,unsigned int node_id)67 nvme_malloc_node(size_t size, size_t align, unsigned int node_id)
68 {
69 	return nvme_mem_alloc_node(size, align, node_id, NULL);
70 }
71 
72 
73 void
nvme_free(void * addr)74 nvme_free(void* addr)
75 {
76 	delete_area(area_for(addr));
77 }
78 
79 
80 phys_addr_t
nvme_mem_vtophys(void * vaddr)81 nvme_mem_vtophys(void* vaddr)
82 {
83 	physical_entry entry;
84 	status_t status = get_memory_map((void*)vaddr, 1, &entry, 1);
85 	if (status != B_OK) {
86 		panic("nvme: get_memory_map failed for %p: %s\n",
87 			(void*)vaddr, strerror(status));
88 		return NVME_VTOPHYS_ERROR;
89 	}
90 
91 	return entry.address;
92 }
93 
94 
95 // #pragma mark - PCI
96 
97 
98 int
nvme_pci_init()99 nvme_pci_init()
100 {
101 	status_t status = get_module(B_PCI_MODULE_NAME,
102 		(module_info**)&sPCIModule);
103 	return status;
104 }
105 
106 
107 int
nvme_pcicfg_read32(struct pci_device * dev,uint32_t * value,uint32_t offset)108 nvme_pcicfg_read32(struct pci_device* dev, uint32_t* value, uint32_t offset)
109 {
110 	*value = sPCIModule->read_pci_config(dev->bus, dev->dev, dev->func, offset,
111 		sizeof(*value));
112 	return 0;
113 }
114 
115 
116 int
nvme_pcicfg_write32(struct pci_device * dev,uint32_t value,uint32_t offset)117 nvme_pcicfg_write32(struct pci_device* dev, uint32_t value, uint32_t offset)
118 {
119 	sPCIModule->write_pci_config(dev->bus, dev->dev, dev->func, offset,
120 		sizeof(value), value);
121 	return 0;
122 }
123 
124 
125 void
nvme_pcicfg_get_bar_addr_len(void * devhandle,unsigned int bar,uint64_t * _addr,uint64_t * _size)126 nvme_pcicfg_get_bar_addr_len(void* devhandle, unsigned int bar,
127 	uint64_t* _addr, uint64_t* _size)
128 {
129 	struct pci_device* dev = (struct pci_device*)devhandle;
130 	pci_info* info = (pci_info*)dev->pci_info;
131 
132 	uint64 addr = info->u.h0.base_registers[bar];
133 	uint64 size = info->u.h0.base_register_sizes[bar];
134 	if ((info->u.h0.base_register_flags[bar] & PCI_address_type) == PCI_address_type_64) {
135 		addr |= (uint64)info->u.h0.base_registers[bar + 1] << 32;
136 		size |= (uint64)info->u.h0.base_register_sizes[bar + 1] << 32;
137 	}
138 
139 	*_addr = addr;
140 	*_size = size;
141 }
142 
143 
144 int
nvme_pcicfg_map_bar(void * devhandle,unsigned int bar,bool read_only,void ** mapped_addr)145 nvme_pcicfg_map_bar(void* devhandle, unsigned int bar, bool read_only,
146 	void** mapped_addr)
147 {
148 	uint64 addr, size;
149 	nvme_pcicfg_get_bar_addr_len(devhandle, bar, &addr, &size);
150 
151 	area_id area = map_physical_memory("nvme mapped bar", (phys_addr_t)addr, (size_t)size,
152 		B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | (read_only ? 0 : B_KERNEL_WRITE_AREA),
153 		mapped_addr);
154 	if (area < B_OK)
155 		return area;
156 
157 	return 0;
158 }
159 
160 
161 int
nvme_pcicfg_map_bar_write_combine(void * devhandle,unsigned int bar,void ** mapped_addr)162 nvme_pcicfg_map_bar_write_combine(void* devhandle, unsigned int bar,
163 	void** mapped_addr)
164 {
165 	status_t status = nvme_pcicfg_map_bar(devhandle, bar, false, mapped_addr);
166 	if (status != 0)
167 		return status;
168 
169 	// Turn on write combining for the area
170 	status = vm_set_area_memory_type(area_for(*mapped_addr),
171 		nvme_mem_vtophys(*mapped_addr), B_WRITE_COMBINING_MEMORY);
172 	if (status != 0)
173 		nvme_pcicfg_unmap_bar(devhandle, bar, *mapped_addr);
174 	return status;
175 }
176 
177 
178 int
nvme_pcicfg_unmap_bar(void * devhandle,unsigned int bar,void * addr)179 nvme_pcicfg_unmap_bar(void* devhandle, unsigned int bar, void* addr)
180 {
181 	return delete_area(area_for(addr));
182 }
183 
184 
185 // #pragma mark - logging
186 
187 
188 void
nvme_log(enum nvme_log_level level,const char * format,...)189 nvme_log(enum nvme_log_level level, const char *format, ...)
190 {
191 	va_list ap;
192 
193 	va_start(ap, format);
194 	nvme_vlog(level, format, ap);
195 	va_end(ap);
196 }
197 
198 
199 void
nvme_vlog(enum nvme_log_level level,const char * format,va_list ap)200 nvme_vlog(enum nvme_log_level level, const char *format, va_list ap)
201 {
202 	dvprintf(format, ap);
203 }
204