1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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. 32 */ 33 34 #include <stdio.h> 35 #include <stdint.h> 36 #include <stdlib.h> 37 #include <stdarg.h> 38 #include <unistd.h> 39 #include <inttypes.h> 40 #include <sys/mman.h> 41 #include <sys/queue.h> 42 43 #include <rte_memory.h> 44 #include <rte_eal.h> 45 #include <rte_eal_memconfig.h> 46 #include <rte_log.h> 47 48 #include "eal_private.h" 49 #include "eal_internal_cfg.h" 50 51 /* 52 * Return a pointer to a read-only table of struct rte_physmem_desc 53 * elements, containing the layout of all addressable physical 54 * memory. The last element of the table contains a NULL address. 55 */ 56 const struct rte_memseg * 57 rte_eal_get_physmem_layout(void) 58 { 59 return rte_eal_get_configuration()->mem_config->memseg; 60 } 61 62 63 /* get the total size of memory */ 64 uint64_t 65 rte_eal_get_physmem_size(void) 66 { 67 const struct rte_mem_config *mcfg; 68 unsigned i = 0; 69 uint64_t total_len = 0; 70 71 /* get pointer to global configuration */ 72 mcfg = rte_eal_get_configuration()->mem_config; 73 74 for (i = 0; i < RTE_MAX_MEMSEG; i++) { 75 if (mcfg->memseg[i].addr == NULL) 76 break; 77 78 total_len += mcfg->memseg[i].len; 79 } 80 81 return total_len; 82 } 83 84 /* Dump the physical memory layout on console */ 85 void 86 rte_dump_physmem_layout(FILE *f) 87 { 88 const struct rte_mem_config *mcfg; 89 unsigned i = 0; 90 91 /* get pointer to global configuration */ 92 mcfg = rte_eal_get_configuration()->mem_config; 93 94 for (i = 0; i < RTE_MAX_MEMSEG; i++) { 95 if (mcfg->memseg[i].addr == NULL) 96 break; 97 98 fprintf(f, "Segment %u: IOVA:0x%"PRIx64", len:%zu, " 99 "virt:%p, socket_id:%"PRId32", " 100 "hugepage_sz:%"PRIu64", nchannel:%"PRIx32", " 101 "nrank:%"PRIx32"\n", i, 102 mcfg->memseg[i].iova, 103 mcfg->memseg[i].len, 104 mcfg->memseg[i].addr, 105 mcfg->memseg[i].socket_id, 106 mcfg->memseg[i].hugepage_sz, 107 mcfg->memseg[i].nchannel, 108 mcfg->memseg[i].nrank); 109 } 110 } 111 112 /* 63 bits is good enough for a sanity check */ 113 #define MAX_DMA_MASK_BITS 63 114 115 /* check memseg iovas are within the required range based on dma mask */ 116 int 117 rte_eal_check_dma_mask(uint8_t maskbits) 118 { 119 120 const struct rte_mem_config *mcfg; 121 uint64_t mask; 122 int i; 123 124 /* sanity check */ 125 if (maskbits > MAX_DMA_MASK_BITS) { 126 RTE_LOG(INFO, EAL, "wrong dma mask size %u (Max: %u)\n", 127 maskbits, MAX_DMA_MASK_BITS); 128 return -1; 129 } 130 131 /* create dma mask */ 132 mask = ~((1ULL << maskbits) - 1); 133 134 /* get pointer to global configuration */ 135 mcfg = rte_eal_get_configuration()->mem_config; 136 137 for (i = 0; i < RTE_MAX_MEMSEG; i++) { 138 if (mcfg->memseg[i].addr == NULL) 139 break; 140 141 if (mcfg->memseg[i].iova & mask) { 142 RTE_LOG(INFO, EAL, 143 "memseg[%d] iova %"PRIx64" out of range:\n", 144 i, mcfg->memseg[i].iova); 145 146 RTE_LOG(INFO, EAL, "\tusing dma mask %"PRIx64"\n", 147 mask); 148 return -1; 149 } 150 } 151 152 return 0; 153 } 154 155 /* return the number of memory channels */ 156 unsigned rte_memory_get_nchannel(void) 157 { 158 return rte_eal_get_configuration()->mem_config->nchannel; 159 } 160 161 /* return the number of memory rank */ 162 unsigned rte_memory_get_nrank(void) 163 { 164 return rte_eal_get_configuration()->mem_config->nrank; 165 } 166 167 static int 168 rte_eal_memdevice_init(void) 169 { 170 struct rte_config *config; 171 172 if (rte_eal_process_type() == RTE_PROC_SECONDARY) 173 return 0; 174 175 config = rte_eal_get_configuration(); 176 config->mem_config->nchannel = internal_config.force_nchannel; 177 config->mem_config->nrank = internal_config.force_nrank; 178 179 return 0; 180 } 181 182 /* Lock page in physical memory and prevent from swapping. */ 183 int 184 rte_mem_lock_page(const void *virt) 185 { 186 unsigned long virtual = (unsigned long)virt; 187 int page_size = getpagesize(); 188 unsigned long aligned = (virtual & ~(page_size - 1)); 189 return mlock((void *)aligned, page_size); 190 } 191 192 /* init memory subsystem */ 193 int 194 rte_eal_memory_init(void) 195 { 196 RTE_LOG(DEBUG, EAL, "Setting up physically contiguous memory...\n"); 197 198 const int retval = rte_eal_process_type() == RTE_PROC_PRIMARY ? 199 rte_eal_hugepage_init() : 200 rte_eal_hugepage_attach(); 201 if (retval < 0) 202 return -1; 203 204 if (internal_config.no_shconf == 0 && rte_eal_memdevice_init() < 0) 205 return -1; 206 207 return 0; 208 } 209