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
lio_toggle_bar1_swapmode(struct octeon_device * oct,uint32_t idx)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
lio_write_bar1_mem8(struct octeon_device * oct,uint32_t reg,uint64_t val)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
lio_read_bar1_mem32(struct octeon_device * oct,uint32_t reg)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
lio_write_bar1_mem32(struct octeon_device * oct,uint32_t reg,uint32_t val)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
lio_read_bar1_mem64(struct octeon_device * oct,uint32_t reg)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
lio_write_bar1_mem64(struct octeon_device * oct,uint32_t reg,uint64_t val)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
lio_pci_fastwrite(struct octeon_device * oct,uint32_t offset,uint8_t * hostbuf,uint32_t len)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
lio_read_bar1_mem8(struct octeon_device * oct,uint32_t reg)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
lio_pci_fastread(struct octeon_device * oct,uint32_t offset,uint8_t * hostbuf,uint32_t len)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
lio_pci_rw_core_mem(struct octeon_device * oct,uint64_t addr,uint8_t * hostbuf,uint32_t len,uint32_t op)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
lio_pci_read_core_mem(struct octeon_device * oct,uint64_t coreaddr,uint8_t * buf,uint32_t len)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
lio_pci_write_core_mem(struct octeon_device * oct,uint64_t coreaddr,uint8_t * buf,uint32_t len)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
lio_read_device_mem64(struct octeon_device * oct,uint64_t coreaddr)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
lio_read_device_mem32(struct octeon_device * oct,uint64_t coreaddr)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
lio_write_device_mem32(struct octeon_device * oct,uint64_t coreaddr,uint32_t val)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