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 28 nvme_mem_init() 29 { 30 /* nothing to do */ 31 return 0; 32 } 33 34 35 void 36 nvme_mem_cleanup() 37 { 38 /* nothing to do */ 39 } 40 41 42 void* 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* 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 74 nvme_free(void* addr) 75 { 76 delete_area(area_for(addr)); 77 } 78 79 80 phys_addr_t 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 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 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 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 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 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 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 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 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 200 nvme_vlog(enum nvme_log_level level, const char *format, va_list ap) 201 { 202 dvprintf(format, ap); 203 } 204