xref: /freebsd/sys/dev/liquidio/base/lio_mem_ops.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
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