1 /* 2 * BSD LICENSE 3 * 4 * Copyright(c) 2017 Cavium, Inc.. 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 Cavium, Inc. 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(S) 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 "lio_bsd.h" 35 #include "lio_common.h" 36 #include "lio_droq.h" 37 #include "lio_iq.h" 38 #include "lio_response_manager.h" 39 #include "lio_device.h" 40 #include "lio_mem_ops.h" 41 42 #define MEMOPS_IDX LIO_MAX_BAR1_MAP_INDEX 43 44 #if BYTE_ORDER == BIG_ENDIAN 45 static inline void 46 lio_toggle_bar1_swapmode(struct octeon_device *oct, uint32_t idx) 47 { 48 uint32_t mask; 49 50 mask = oct->fn_list.bar1_idx_read(oct, idx); 51 mask = (mask & 0x2) ? (mask & ~2) : (mask | 2); 52 oct->fn_list.bar1_idx_write(oct, idx, mask); 53 } 54 55 #else /* BYTE_ORDER != BIG_ENDIAN */ 56 #define lio_toggle_bar1_swapmode(oct, idx) 57 #endif /* BYTE_ORDER == BIG_ENDIAN */ 58 59 static inline void 60 lio_write_bar1_mem8(struct octeon_device *oct, uint32_t reg, uint64_t val) 61 { 62 63 bus_space_write_1(oct->mem_bus_space[1].tag, 64 oct->mem_bus_space[1].handle, reg, val); 65 } 66 67 #ifdef __i386__ 68 static inline uint32_t 69 lio_read_bar1_mem32(struct octeon_device *oct, uint32_t reg) 70 { 71 72 return (bus_space_read_4(oct->mem_bus_space[1].tag, 73 oct->mem_bus_space[1].handle, reg)); 74 } 75 76 static inline void 77 lio_write_bar1_mem32(struct octeon_device *oct, uint32_t reg, uint32_t val) 78 { 79 80 bus_space_write_4(oct->mem_bus_space[1].tag, 81 oct->mem_bus_space[1].handle, reg, val); 82 } 83 #endif 84 85 static inline uint64_t 86 lio_read_bar1_mem64(struct octeon_device *oct, uint32_t reg) 87 { 88 89 #ifdef __i386__ 90 return (lio_read_bar1_mem32(oct, reg) | 91 ((uint64_t)lio_read_bar1_mem32(oct, reg + 4) << 32)); 92 #else 93 return (bus_space_read_8(oct->mem_bus_space[1].tag, 94 oct->mem_bus_space[1].handle, reg)); 95 #endif 96 } 97 98 static inline void 99 lio_write_bar1_mem64(struct octeon_device *oct, uint32_t reg, uint64_t val) 100 { 101 102 #ifdef __i386__ 103 lio_write_bar1_mem32(oct, reg, (uint32_t)val); 104 lio_write_bar1_mem32(oct, reg + 4, val >> 32); 105 #else 106 bus_space_write_8(oct->mem_bus_space[1].tag, 107 oct->mem_bus_space[1].handle, reg, val); 108 #endif 109 } 110 111 static void 112 lio_pci_fastwrite(struct octeon_device *oct, uint32_t offset, 113 uint8_t *hostbuf, uint32_t len) 114 { 115 116 while ((len) && ((unsigned long)offset) & 7) { 117 lio_write_bar1_mem8(oct, offset++, *(hostbuf++)); 118 len--; 119 } 120 121 lio_toggle_bar1_swapmode(oct, MEMOPS_IDX); 122 123 while (len >= 8) { 124 lio_write_bar1_mem64(oct, offset, *((uint64_t *)hostbuf)); 125 offset += 8; 126 hostbuf += 8; 127 len -= 8; 128 } 129 130 lio_toggle_bar1_swapmode(oct, MEMOPS_IDX); 131 132 while (len--) 133 lio_write_bar1_mem8(oct, offset++, *(hostbuf++)); 134 } 135 136 static inline uint64_t 137 lio_read_bar1_mem8(struct octeon_device *oct, uint32_t reg) 138 { 139 140 return (bus_space_read_1(oct->mem_bus_space[1].tag, 141 oct->mem_bus_space[1].handle, reg)); 142 } 143 144 static void 145 lio_pci_fastread(struct octeon_device *oct, uint32_t offset, 146 uint8_t *hostbuf, uint32_t len) 147 { 148 149 while ((len) && ((unsigned long)offset) & 7) { 150 *(hostbuf++) = lio_read_bar1_mem8(oct, offset++); 151 len--; 152 } 153 154 lio_toggle_bar1_swapmode(oct, MEMOPS_IDX); 155 156 while (len >= 8) { 157 *((uint64_t *)hostbuf) = lio_read_bar1_mem64(oct, offset); 158 offset += 8; 159 hostbuf += 8; 160 len -= 8; 161 } 162 163 lio_toggle_bar1_swapmode(oct, MEMOPS_IDX); 164 165 while (len--) 166 *(hostbuf++) = lio_read_bar1_mem8(oct, offset++); 167 } 168 169 /* Core mem read/write with temporary bar1 settings. */ 170 /* op = 1 to read, op = 0 to write. */ 171 static void 172 lio_pci_rw_core_mem(struct octeon_device *oct, uint64_t addr, 173 uint8_t *hostbuf, uint32_t len, uint32_t op) 174 { 175 uint64_t static_mapping_base; 176 uint32_t copy_len = 0, index_reg_val = 0; 177 uint32_t offset; 178 179 static_mapping_base = oct->console_nb_info.dram_region_base; 180 181 if (static_mapping_base && static_mapping_base == 182 (addr & 0xFFFFFFFFFFC00000ULL)) { 183 int bar1_index = oct->console_nb_info.bar1_index; 184 185 offset = (bar1_index << 22) + (addr & 0x3fffff); 186 187 if (op) 188 lio_pci_fastread(oct, offset, hostbuf, len); 189 else 190 lio_pci_fastwrite(oct, offset, hostbuf, len); 191 192 return; 193 } 194 mtx_lock(&oct->mem_access_lock); 195 196 /* Save the original index reg value. */ 197 index_reg_val = oct->fn_list.bar1_idx_read(oct, MEMOPS_IDX); 198 do { 199 oct->fn_list.bar1_idx_setup(oct, addr, MEMOPS_IDX, 1); 200 offset = (MEMOPS_IDX << 22) + (addr & 0x3fffff); 201 202 /* 203 * If operation crosses a 4MB boundary, split the transfer 204 * at the 4MB boundary. 205 */ 206 if (((addr + len - 1) & ~(0x3fffff)) != (addr & ~(0x3fffff))) { 207 copy_len = (uint32_t)(((addr & ~(0x3fffff)) + 208 (MEMOPS_IDX << 22)) - addr); 209 } else { 210 copy_len = len; 211 } 212 213 if (op) { /* read from core */ 214 lio_pci_fastread(oct, offset, hostbuf, 215 copy_len); 216 } else { 217 lio_pci_fastwrite(oct, offset, hostbuf, 218 copy_len); 219 } 220 221 len -= copy_len; 222 addr += copy_len; 223 hostbuf += copy_len; 224 225 } while (len); 226 227 oct->fn_list.bar1_idx_write(oct, MEMOPS_IDX, index_reg_val); 228 229 mtx_unlock(&oct->mem_access_lock); 230 } 231 232 void 233 lio_pci_read_core_mem(struct octeon_device *oct, uint64_t coreaddr, 234 uint8_t *buf, uint32_t len) 235 { 236 237 lio_pci_rw_core_mem(oct, coreaddr, buf, len, 1); 238 } 239 240 void 241 lio_pci_write_core_mem(struct octeon_device *oct, uint64_t coreaddr, 242 uint8_t *buf, uint32_t len) 243 { 244 245 lio_pci_rw_core_mem(oct, coreaddr, buf, len, 0); 246 } 247 248 uint64_t 249 lio_read_device_mem64(struct octeon_device *oct, uint64_t coreaddr) 250 { 251 __be64 ret; 252 253 lio_pci_rw_core_mem(oct, coreaddr, (uint8_t *)&ret, 8, 1); 254 255 return (be64toh(ret)); 256 } 257 258 uint32_t 259 lio_read_device_mem32(struct octeon_device *oct, uint64_t coreaddr) 260 { 261 __be32 ret; 262 263 lio_pci_rw_core_mem(oct, coreaddr, (uint8_t *)&ret, 4, 1); 264 265 return (be32toh(ret)); 266 } 267 268 void 269 lio_write_device_mem32(struct octeon_device *oct, uint64_t coreaddr, 270 uint32_t val) 271 { 272 __be32 t = htobe32(val); 273 274 lio_pci_rw_core_mem(oct, coreaddr, (uint8_t *)&t, 4, 0); 275 } 276