Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * Copyright (C) 2020 Marvell International Ltd. |
| 4 | */ |
| 5 | |
| 6 | #ifndef __CVMX_HELPER_UTIL_H__ |
| 7 | #define __CVMX_HELPER_UTIL_H__ |
| 8 | |
| 9 | #include "cvmx-mio-defs.h" |
| 10 | #include "cvmx-helper.h" |
| 11 | #include "cvmx-fpa.h" |
| 12 | |
| 13 | typedef char cvmx_pknd_t; |
| 14 | typedef char cvmx_bpid_t; |
| 15 | |
| 16 | #define CVMX_INVALID_PKND ((cvmx_pknd_t)-1) |
| 17 | #define CVMX_INVALID_BPID ((cvmx_bpid_t)-1) |
| 18 | #define CVMX_MAX_PKND ((cvmx_pknd_t)64) |
| 19 | #define CVMX_MAX_BPID ((cvmx_bpid_t)64) |
| 20 | |
| 21 | #define CVMX_HELPER_MAX_IFACE 11 |
| 22 | #define CVMX_HELPER_MAX_PORTS 16 |
| 23 | |
| 24 | /* Maximum range for normalized (a.k.a. IPD) port numbers (12-bit field) */ |
| 25 | #define CVMX_PKO3_IPD_NUM_MAX 0x1000 //FIXME- take it from someplace else ? |
| 26 | #define CVMX_PKO3_DQ_NUM_MAX 0x400 // 78xx has 1024 queues |
| 27 | |
| 28 | #define CVMX_PKO3_IPD_PORT_NULL (CVMX_PKO3_IPD_NUM_MAX - 1) |
| 29 | #define CVMX_PKO3_IPD_PORT_LOOP 0 |
| 30 | |
| 31 | struct cvmx_xport { |
| 32 | int node; |
| 33 | int port; |
| 34 | }; |
| 35 | |
| 36 | typedef struct cvmx_xport cvmx_xport_t; |
| 37 | |
| 38 | static inline struct cvmx_xport cvmx_helper_ipd_port_to_xport(int ipd_port) |
| 39 | { |
| 40 | struct cvmx_xport r; |
| 41 | |
| 42 | r.port = ipd_port & (CVMX_PKO3_IPD_NUM_MAX - 1); |
| 43 | r.node = (ipd_port >> 12) & CVMX_NODE_MASK; |
| 44 | return r; |
| 45 | } |
| 46 | |
| 47 | static inline int cvmx_helper_node_to_ipd_port(int node, int index) |
| 48 | { |
| 49 | return (node << 12) + index; |
| 50 | } |
| 51 | |
| 52 | struct cvmx_xdq { |
| 53 | int node; |
| 54 | int queue; |
| 55 | }; |
| 56 | |
| 57 | typedef struct cvmx_xdq cvmx_xdq_t; |
| 58 | |
| 59 | static inline struct cvmx_xdq cvmx_helper_queue_to_xdq(int queue) |
| 60 | { |
| 61 | struct cvmx_xdq r; |
| 62 | |
| 63 | r.queue = queue & (CVMX_PKO3_DQ_NUM_MAX - 1); |
| 64 | r.node = (queue >> 10) & CVMX_NODE_MASK; |
| 65 | return r; |
| 66 | } |
| 67 | |
| 68 | static inline int cvmx_helper_node_to_dq(int node, int queue) |
| 69 | { |
| 70 | return (node << 10) + queue; |
| 71 | } |
| 72 | |
| 73 | struct cvmx_xiface { |
| 74 | int node; |
| 75 | int interface; |
| 76 | }; |
| 77 | |
| 78 | typedef struct cvmx_xiface cvmx_xiface_t; |
| 79 | |
| 80 | /** |
| 81 | * Return node and interface number from XIFACE. |
| 82 | * |
| 83 | * @param xiface interface with node information |
| 84 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 85 | * Return: struct that contains node and interface number. |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 86 | */ |
| 87 | static inline struct cvmx_xiface cvmx_helper_xiface_to_node_interface(int xiface) |
| 88 | { |
| 89 | cvmx_xiface_t interface_node; |
| 90 | |
| 91 | /* |
| 92 | * If the majic number 0xde0000 is not present in the |
| 93 | * interface, then assume it is node 0. |
| 94 | */ |
| 95 | |
| 96 | if (((xiface >> 0x8) & 0xff) == 0xde) { |
| 97 | interface_node.node = (xiface >> 16) & CVMX_NODE_MASK; |
| 98 | interface_node.interface = xiface & 0xff; |
| 99 | } else { |
| 100 | interface_node.node = cvmx_get_node_num(); |
| 101 | interface_node.interface = xiface & 0xff; |
| 102 | } |
| 103 | return interface_node; |
| 104 | } |
| 105 | |
| 106 | /* Used internally only*/ |
| 107 | static inline bool __cvmx_helper_xiface_is_null(int xiface) |
| 108 | { |
| 109 | return (xiface & 0xff) == 0xff; |
| 110 | } |
| 111 | |
| 112 | #define __CVMX_XIFACE_NULL 0xff |
| 113 | |
| 114 | /** |
| 115 | * Return interface with majic number and node information (XIFACE) |
| 116 | * |
| 117 | * @param node node of the interface referred to |
| 118 | * @param interface interface to use. |
| 119 | * |
| 120 | * @return |
| 121 | */ |
| 122 | static inline int cvmx_helper_node_interface_to_xiface(int node, int interface) |
| 123 | { |
| 124 | return ((node & CVMX_NODE_MASK) << 16) | (0xde << 8) | (interface & 0xff); |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * Free the pip packet buffers contained in a work queue entry. |
| 129 | * The work queue entry is not freed. |
| 130 | * |
| 131 | * @param work Work queue entry with packet to free |
| 132 | */ |
| 133 | static inline void cvmx_helper_free_pip_pkt_data(cvmx_wqe_t *work) |
| 134 | { |
| 135 | u64 number_buffers; |
| 136 | cvmx_buf_ptr_t buffer_ptr; |
| 137 | cvmx_buf_ptr_t next_buffer_ptr; |
| 138 | u64 start_of_buffer; |
| 139 | |
| 140 | number_buffers = work->word2.s.bufs; |
| 141 | if (number_buffers == 0) |
| 142 | return; |
| 143 | |
| 144 | buffer_ptr = work->packet_ptr; |
| 145 | |
| 146 | /* Since the number of buffers is not zero, we know this is not a dynamic |
| 147 | short packet. We need to check if it is a packet received with |
| 148 | IPD_CTL_STATUS[NO_WPTR]. If this is true, we need to free all buffers |
| 149 | except for the first one. The caller doesn't expect their WQE pointer |
| 150 | to be freed */ |
| 151 | start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; |
| 152 | if (cvmx_ptr_to_phys(work) == start_of_buffer) { |
| 153 | next_buffer_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); |
| 154 | buffer_ptr = next_buffer_ptr; |
| 155 | number_buffers--; |
| 156 | } |
| 157 | |
| 158 | while (number_buffers--) { |
| 159 | /* Remember the back pointer is in cache lines, not 64bit words */ |
| 160 | start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; |
| 161 | /* Read pointer to next buffer before we free the current buffer. */ |
| 162 | next_buffer_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); |
| 163 | cvmx_fpa_free(cvmx_phys_to_ptr(start_of_buffer), buffer_ptr.s.pool, 0); |
| 164 | buffer_ptr = next_buffer_ptr; |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | /** |
| 169 | * Free the pki packet buffers contained in a work queue entry. |
| 170 | * If first packet buffer contains wqe, wqe gets freed too so do not access |
| 171 | * wqe after calling this function. |
| 172 | * This function asssumes that buffers to be freed are from |
| 173 | * Naturally aligned pool/aura. |
| 174 | * It does not use don't write back. |
| 175 | * @param work Work queue entry with packet to free |
| 176 | */ |
| 177 | static inline void cvmx_helper_free_pki_pkt_data(cvmx_wqe_t *work) |
| 178 | { |
| 179 | u64 number_buffers; |
| 180 | u64 start_of_buffer; |
| 181 | cvmx_buf_ptr_pki_t next_buffer_ptr; |
| 182 | cvmx_buf_ptr_pki_t buffer_ptr; |
| 183 | cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; |
| 184 | |
| 185 | if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { |
| 186 | return; |
| 187 | } |
| 188 | /* Make sure errata pki-20776 has been applied*/ |
| 189 | cvmx_wqe_pki_errata_20776(work); |
| 190 | buffer_ptr = wqe->packet_ptr; |
| 191 | number_buffers = cvmx_wqe_get_bufs(work); |
| 192 | |
| 193 | while (number_buffers--) { |
| 194 | /* FIXME: change WQE function prototype */ |
| 195 | unsigned int x = cvmx_wqe_get_aura(work); |
| 196 | cvmx_fpa3_gaura_t aura = __cvmx_fpa3_gaura(x >> 10, x & 0x3ff); |
| 197 | /* XXX- assumes the buffer is cache-line aligned and naturally aligned mode*/ |
| 198 | start_of_buffer = (buffer_ptr.addr >> 7) << 7; |
| 199 | /* Read pointer to next buffer before we free the current buffer. */ |
| 200 | next_buffer_ptr = *(cvmx_buf_ptr_pki_t *)cvmx_phys_to_ptr(buffer_ptr.addr - 8); |
| 201 | /* FPA AURA comes from WQE, includes node */ |
| 202 | cvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer), aura, 0); |
| 203 | buffer_ptr = next_buffer_ptr; |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Free the pki wqe entry buffer. |
| 209 | * If wqe buffers contains first packet buffer, wqe does not get freed here. |
| 210 | * This function asssumes that buffers to be freed are from |
| 211 | * Naturally aligned pool/aura. |
| 212 | * It does not use don't write back. |
| 213 | * @param work Work queue entry to free |
| 214 | */ |
| 215 | static inline void cvmx_wqe_pki_free(cvmx_wqe_t *work) |
| 216 | { |
| 217 | cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; |
| 218 | unsigned int x; |
| 219 | cvmx_fpa3_gaura_t aura; |
| 220 | |
| 221 | if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { |
| 222 | return; |
| 223 | } |
| 224 | /* Do nothing if the first packet buffer shares WQE buffer */ |
| 225 | if (!wqe->packet_ptr.packet_outside_wqe) |
| 226 | return; |
| 227 | |
| 228 | /* FIXME change WQE function prototype */ |
| 229 | x = cvmx_wqe_get_aura(work); |
| 230 | aura = __cvmx_fpa3_gaura(x >> 10, x & 0x3ff); |
| 231 | |
| 232 | cvmx_fpa3_free(work, aura, 0); |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * Convert a interface mode into a human readable string |
| 237 | * |
| 238 | * @param mode Mode to convert |
| 239 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 240 | * Return: String |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 241 | */ |
| 242 | const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode); |
| 243 | |
| 244 | /** |
| 245 | * Debug routine to dump the packet structure to the console |
| 246 | * |
| 247 | * @param work Work queue entry containing the packet to dump |
| 248 | * @return |
| 249 | */ |
| 250 | int cvmx_helper_dump_packet(cvmx_wqe_t *work); |
| 251 | |
| 252 | /** |
| 253 | * Get the version of the CVMX libraries. |
| 254 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 255 | * Return: Version string. Note this buffer is allocated statically |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 256 | * and will be shared by all callers. |
| 257 | */ |
| 258 | const char *cvmx_helper_get_version(void); |
| 259 | |
| 260 | /** |
| 261 | * @INTERNAL |
| 262 | * Setup the common GMX settings that determine the number of |
| 263 | * ports. These setting apply to almost all configurations of all |
| 264 | * chips. |
| 265 | * |
| 266 | * @param xiface Interface to configure |
| 267 | * @param num_ports Number of ports on the interface |
| 268 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 269 | * Return: Zero on success, negative on failure |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 270 | */ |
| 271 | int __cvmx_helper_setup_gmx(int xiface, int num_ports); |
| 272 | |
| 273 | /** |
| 274 | * @INTERNAL |
| 275 | * Get the number of pko_ports on an interface. |
| 276 | * |
| 277 | * @param interface |
| 278 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 279 | * Return: the number of pko_ports on the interface. |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 280 | */ |
| 281 | int __cvmx_helper_get_num_pko_ports(int interface); |
| 282 | |
| 283 | /** |
| 284 | * Returns the IPD port number for a port on the given |
| 285 | * interface. |
| 286 | * |
| 287 | * @param interface Interface to use |
| 288 | * @param port Port on the interface |
| 289 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 290 | * Return: IPD port number |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 291 | */ |
| 292 | int cvmx_helper_get_ipd_port(int interface, int port); |
| 293 | |
| 294 | /** |
| 295 | * Returns the PKO port number for a port on the given interface, |
| 296 | * This is the base pko_port for o68 and ipd_port for older models. |
| 297 | * |
| 298 | * @param interface Interface to use |
| 299 | * @param port Port on the interface |
| 300 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 301 | * Return: PKO port number and -1 on error. |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 302 | */ |
| 303 | int cvmx_helper_get_pko_port(int interface, int port); |
| 304 | |
| 305 | /** |
| 306 | * Returns the IPD/PKO port number for the first port on the given |
| 307 | * interface. |
| 308 | * |
| 309 | * @param interface Interface to use |
| 310 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 311 | * Return: IPD/PKO port number |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 312 | */ |
| 313 | static inline int cvmx_helper_get_first_ipd_port(int interface) |
| 314 | { |
| 315 | return cvmx_helper_get_ipd_port(interface, 0); |
| 316 | } |
| 317 | |
| 318 | int cvmx_helper_ports_on_interface(int interface); |
| 319 | |
| 320 | /** |
| 321 | * Returns the IPD/PKO port number for the last port on the given |
| 322 | * interface. |
| 323 | * |
| 324 | * @param interface Interface to use |
| 325 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 326 | * Return: IPD/PKO port number |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 327 | * |
| 328 | * Note: for o68, the last ipd port on an interface does not always equal to |
| 329 | * the first plus the number of ports as the ipd ports are not contiguous in |
| 330 | * some cases, e.g., SGMII. |
| 331 | * |
| 332 | * Note: code that makes the assumption of contiguous ipd port numbers needs to |
| 333 | * be aware of this. |
| 334 | */ |
| 335 | static inline int cvmx_helper_get_last_ipd_port(int interface) |
| 336 | { |
| 337 | return cvmx_helper_get_ipd_port(interface, cvmx_helper_ports_on_interface(interface) - 1); |
| 338 | } |
| 339 | |
| 340 | /** |
| 341 | * Free the packet buffers contained in a work queue entry. |
| 342 | * The work queue entry is not freed. |
| 343 | * Note that this function will not free the work queue entry |
| 344 | * even if it contains a non-redundant data packet, and hence |
| 345 | * it is not really comparable to how the PKO would free a packet |
| 346 | * buffers if requested. |
| 347 | * |
| 348 | * @param work Work queue entry with packet to free |
| 349 | */ |
| 350 | void cvmx_helper_free_packet_data(cvmx_wqe_t *work); |
| 351 | |
| 352 | /** |
| 353 | * Returns the interface number for an IPD/PKO port number. |
| 354 | * |
| 355 | * @param ipd_port IPD/PKO port number |
| 356 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 357 | * Return: Interface number |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 358 | */ |
| 359 | int cvmx_helper_get_interface_num(int ipd_port); |
| 360 | |
| 361 | /** |
| 362 | * Returns the interface index number for an IPD/PKO port |
| 363 | * number. |
| 364 | * |
| 365 | * @param ipd_port IPD/PKO port number |
| 366 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 367 | * Return: Interface index number |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 368 | */ |
| 369 | int cvmx_helper_get_interface_index_num(int ipd_port); |
| 370 | |
| 371 | /** |
| 372 | * Get port kind for a given port in an interface. |
| 373 | * |
| 374 | * @param xiface Interface |
| 375 | * @param index index of the port in the interface |
| 376 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 377 | * Return: port kind on sucicess and -1 on failure |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 378 | */ |
| 379 | int cvmx_helper_get_pknd(int xiface, int index); |
| 380 | |
| 381 | /** |
| 382 | * Get bpid for a given port in an interface. |
| 383 | * |
| 384 | * @param interface Interface |
| 385 | * @param port index of the port in the interface |
| 386 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 387 | * Return: port kind on sucicess and -1 on failure |
Aaron Williams | 3bda89d | 2020-12-11 17:05:24 +0100 | [diff] [blame] | 388 | */ |
| 389 | int cvmx_helper_get_bpid(int interface, int port); |
| 390 | |
| 391 | /** |
| 392 | * Internal functions. |
| 393 | */ |
| 394 | int __cvmx_helper_post_init_interfaces(void); |
| 395 | int cvmx_helper_setup_red(int pass_thresh, int drop_thresh); |
| 396 | void cvmx_helper_show_stats(int port); |
| 397 | |
| 398 | /* |
| 399 | * Return number of array alements |
| 400 | */ |
| 401 | #define NUM_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) |
| 402 | |
| 403 | /** |
| 404 | * Prints out a buffer with the address, hex bytes, and ASCII |
| 405 | * |
| 406 | * @param addr Start address to print on the left |
| 407 | * @param[in] buffer array of bytes to print |
| 408 | * @param count Number of bytes to print |
| 409 | */ |
| 410 | void cvmx_print_buffer_u8(unsigned int addr, const u8 *buffer, size_t count); |
| 411 | |
| 412 | #endif /* __CVMX_HELPER_H__ */ |