1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40/** 41 * @file 42 * 43 * Support library for the hardware Packet Output unit. 44 * 45 * <hr>$Revision: 70030 $<hr> 46 */ 47#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 48#include <asm/octeon/cvmx.h> 49#include <asm/octeon/cvmx-config.h> 50#include <asm/octeon/cvmx-pko.h> 51#include <asm/octeon/cvmx-helper.h> 52#include <asm/octeon/cvmx-helper-cfg.h> 53#include <asm/octeon/cvmx-clock.h> 54#else 55#if !defined(__FreeBSD__) || !defined(_KERNEL) 56#include "executive-config.h" 57#endif 58#include "cvmx.h" 59#include "cvmx-sysinfo.h" 60#if !defined(__FreeBSD__) || !defined(_KERNEL) 61#include "cvmx-config.h" 62#endif 63#include "cvmx-pko.h" 64#include "cvmx-helper.h" 65#include "cvmx-helper-cfg.h" 66#endif 67 68/* #define PKO_DEBUG */ 69 70#define CVMX_PKO_NQ_PER_PORT_MAX 32 71 72/** 73 * Internal state of packet output 74 */ 75#ifdef CVMX_ENABLE_PKO_FUNCTIONS 76 77/* 78 * PKO port iterator 79 */ 80#define CVMX_PKO_FOR_EACH_PORT_BEGIN do { \ 81 int XIT_pko_port; \ 82 for (XIT_pko_port = 0; XIT_pko_port < CVMX_HELPER_CFG_MAX_PKO_PORT; \ 83 XIT_pko_port++) \ 84 { \ 85 if (__cvmx_helper_cfg_pko_queue_base(XIT_pko_port) != \ 86 CVMX_HELPER_CFG_INVALID_VALUE) 87 88#define CVMX_PKO_FOR_EACH_PORT_END } /* for */ \ 89 } while (0) 90 91/* 92 * @INTERNAL 93 * 94 * Get INT for a port 95 * 96 * @param interface 97 * @param index 98 * @return the INT value on success and -1 on error 99 */ 100static int __cvmx_pko_int(int interface, int index) 101{ 102 cvmx_helper_cfg_assert(interface < CVMX_HELPER_CFG_MAX_IFACE); 103 cvmx_helper_cfg_assert(index >= 0); 104 105 switch (interface) 106 { 107 case 0: 108 cvmx_helper_cfg_assert(index < 4); 109 return index; 110 break; 111 case 1: 112 cvmx_helper_cfg_assert(index == 0); 113 return 4; 114 break; 115 case 2: 116 cvmx_helper_cfg_assert(index < 4); 117 return index + 8; 118 break; 119 case 3: 120 cvmx_helper_cfg_assert(index < 4); 121 return index + 0xC; 122 break; 123 case 4: 124 cvmx_helper_cfg_assert(index < 4); 125 return index + 0x10; 126 break; 127 case 5: 128 cvmx_helper_cfg_assert(index < 256); 129 return 0x1C; 130 break; 131 case 6: 132 cvmx_helper_cfg_assert(index < 256); 133 return 0x1D; 134 break; 135 case 7: 136 cvmx_helper_cfg_assert(index < 32); 137 return 0x1E; 138 break; 139 case 8: 140 cvmx_helper_cfg_assert(index < 8); 141 return 0x1F; 142 break; 143 } 144 145 return -1; 146} 147 148int cvmx_pko_get_base_pko_port(int interface, int index) 149{ 150 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 151 return __cvmx_helper_cfg_pko_port_base(interface, index); 152 else 153 return cvmx_helper_get_ipd_port(interface, index); 154} 155#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 156EXPORT_SYMBOL(cvmx_pko_get_base_pko_port); 157#endif 158 159int cvmx_pko_get_num_pko_ports(int interface, int index) 160{ 161 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 162 return __cvmx_helper_cfg_pko_port_num(interface, index); 163 else 164 return 1; 165} 166#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 167EXPORT_SYMBOL(cvmx_pko_get_num_pko_ports); 168#endif 169 170int cvmx_pko_get_base_queue(int port) 171{ 172 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 173 { 174 return __cvmx_helper_cfg_pko_queue_base( 175 cvmx_helper_cfg_ipd2pko_port_base(port)); 176 } 177 else 178 return cvmx_pko_get_base_queue_per_core(port, 0); 179} 180#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 181EXPORT_SYMBOL(cvmx_pko_get_base_queue); 182#endif 183 184/** 185 * For a given PKO port number, return the base output queue 186 * for the port. 187 * 188 * @param pko_port PKO port number 189 * @return Base output queue 190 */ 191int cvmx_pko_get_base_queue_pkoid(int pko_port) 192{ 193 return __cvmx_helper_cfg_pko_queue_base(pko_port); 194} 195 196/** 197 * For a given PKO port number, return the number of output queues 198 * for the port. 199 * 200 * @param pko_port PKO port number 201 * @return the number of output queues 202 */ 203int cvmx_pko_get_num_queues_pkoid(int pko_port) 204{ 205 return __cvmx_helper_cfg_pko_queue_num(pko_port); 206} 207 208int cvmx_pko_get_num_queues(int port) 209{ 210 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 211 { 212 return __cvmx_helper_cfg_pko_queue_num( 213 cvmx_helper_cfg_ipd2pko_port_base(port)); 214 } 215 else 216 { 217 if (port < 16) 218 return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0; 219 else if (port < 32) 220 return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1; 221 else if (port < 36) 222 return CVMX_PKO_QUEUES_PER_PORT_PCI; 223 else if (port < 40) 224 return CVMX_PKO_QUEUES_PER_PORT_LOOP; 225 else if (port < 42) 226 return CVMX_PKO_QUEUES_PER_PORT_SRIO0; 227 else if (port < 44) 228 return CVMX_PKO_QUEUES_PER_PORT_SRIO1; 229 else if (port < 46) 230 return CVMX_PKO_QUEUES_PER_PORT_SRIO2; 231 } 232 return 0; 233} 234#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 235EXPORT_SYMBOL(cvmx_pko_get_num_queues); 236#endif 237 238#ifdef PKO_DEBUG 239/** 240 * Show queues for the internal ports 241 */ 242void cvmx_pko_show_queue_map(void) 243{ 244 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 245 { 246 CVMX_PKO_FOR_EACH_PORT_BEGIN { 247 cvmx_dprintf("pko_port %d (interface%d index%d) has %d queues (queue base = %d)\n", 248 XIT_pko_port, 249 __cvmx_helper_cfg_pko_port_interface(XIT_pko_port), 250 __cvmx_helper_cfg_pko_port_index(XIT_pko_port), 251 __cvmx_helper_cfg_pko_queue_num(XIT_pko_port), 252 __cvmx_helper_cfg_pko_queue_base(XIT_pko_port)); 253 } CVMX_PKO_FOR_EACH_PORT_END; 254 } 255 else 256 { 257 int core, port; 258 int pko_output_ports; 259 260 pko_output_ports = 36; 261 cvmx_dprintf("port"); 262 for(port = 0; port < pko_output_ports; port++) 263 cvmx_dprintf("%3d ", port); 264 cvmx_dprintf("\n"); 265 266 for(core = 0; core < CVMX_MAX_CORES; core++) 267 { 268 cvmx_dprintf("\n%2d: ", core); 269 for(port = 0; port < pko_output_ports; port++) 270 cvmx_dprintf("%3d ", 271 cvmx_pko_get_base_queue_per_core(port, core)); 272 } 273 cvmx_dprintf("\n"); 274 275 } 276} 277#endif /* PKO_DEBUG */ 278 279/* 280 * Configure queues for an internal port. 281 * @INTERNAL 282 * @param pko_port PKO internal port number 283 * Note: o68 only 284 */ 285static void __cvmx_pko_iport_config(int pko_port) 286{ 287 int queue, base_queue, num_queues; 288 int static_priority_base; 289 int static_priority_end; 290 cvmx_pko_mem_iqueue_ptrs_t config; 291 uint64_t *buf_ptr = NULL; 292 uint64_t priorities[CVMX_PKO_NQ_PER_PORT_MAX] = { 293 [0 ... CVMX_PKO_NQ_PER_PORT_MAX - 1] = 8 }; 294 295 static_priority_base = -1; 296 static_priority_end = -1; 297 base_queue = __cvmx_helper_cfg_pko_queue_base(pko_port); 298 num_queues = __cvmx_helper_cfg_pko_queue_num(pko_port); 299 300 /* 301 * Give the user a chance to override the per queue priorities. 302 */ 303 if (cvmx_override_pko_queue_priority) 304 cvmx_override_pko_queue_priority(pko_port, &priorities[0]); 305 306 /* 307 * static queue priority validation 308 */ 309 for (queue = 0; queue < num_queues; queue++) 310 { 311 if (static_priority_base == -1 && 312 priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 313 static_priority_base = queue; 314 315 if (static_priority_base != -1 && 316 static_priority_end == -1 && 317 priorities[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && 318 queue) 319 static_priority_end = queue - 1; 320 else if (static_priority_base != -1 && 321 static_priority_end == -1 && 322 queue == num_queues - 1) 323 static_priority_end = queue; /* all queues are static priority */ 324 325 /* 326 * Check to make sure all static priority queues are contiguous. 327 * Also catches some cases of static priorites not starting from 328 * queue 0. 329 */ 330 if (static_priority_end != -1 && 331 (int)queue > static_priority_end && 332 priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 333 { 334 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority " 335 "queues aren't contiguous or don't start at base queue. " 336 "q: %d, eq: %d\n", (int)queue, static_priority_end); 337 } 338 if (static_priority_base > 0) 339 { 340 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority " 341 "queues don't start at base queue. sq: %d\n", 342 static_priority_base); 343 } 344 } 345 346 /* 347 * main loop to set the fields of CVMX_PKO_MEM_IQUEUE_PTRS for 348 * each queue 349 */ 350 for (queue = 0; queue < num_queues; queue++) 351 { 352 config.u64 = 0; 353 config.s.index = queue; 354 config.s.qid = base_queue + queue; 355 config.s.ipid = pko_port; 356 config.s.tail = (queue == (num_queues - 1)); 357 config.s.s_tail = (queue == static_priority_end); 358 config.s.static_p = (static_priority_base >= 0); 359 config.s.static_q = (queue <= static_priority_end); 360 361 /* 362 * Convert the priority into an enable bit field. 363 * Try to space the bits out evenly so the packet 364 * don't get grouped up. 365 */ 366 switch ((int)priorities[queue]) 367 { 368 case 0: config.s.qos_mask = 0x00; break; 369 case 1: config.s.qos_mask = 0x01; break; 370 case 2: config.s.qos_mask = 0x11; break; 371 case 3: config.s.qos_mask = 0x49; break; 372 case 4: config.s.qos_mask = 0x55; break; 373 case 5: config.s.qos_mask = 0x57; break; 374 case 6: config.s.qos_mask = 0x77; break; 375 case 7: config.s.qos_mask = 0x7f; break; 376 case 8: config.s.qos_mask = 0xff; break; 377 case CVMX_PKO_QUEUE_STATIC_PRIORITY: 378 config.s.qos_mask = 0xff; 379 break; 380 default: 381 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: " 382 "Invalid priority %llu\n", 383 (unsigned long long)priorities[queue]); 384 config.s.qos_mask = 0xff; 385 break; 386 } 387 388 /* 389 * The command queues 390 */ 391 { 392 cvmx_cmd_queue_result_t cmd_res; 393 394 cmd_res = cvmx_cmd_queue_initialize( 395 CVMX_CMD_QUEUE_PKO(base_queue + queue), 396 CVMX_PKO_MAX_QUEUE_DEPTH, 397 CVMX_FPA_OUTPUT_BUFFER_POOL, 398 (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - 399 CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); 400 401 if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) 402 { 403 switch (cmd_res) 404 { 405 case CVMX_CMD_QUEUE_NO_MEMORY: 406 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Unable to allocate output buffer."); 407 break; 408 case CVMX_CMD_QUEUE_ALREADY_SETUP: 409 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Port already setup"); 410 break; 411 case CVMX_CMD_QUEUE_INVALID_PARAM: 412 default: 413 cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Command queue initialization failed."); 414 break; 415 } 416 cvmx_dprintf(" pko_port%d base_queue%d num_queues%d queue%d.\n", 417 pko_port, base_queue, num_queues, queue); 418 } 419 420 buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer( 421 CVMX_CMD_QUEUE_PKO(base_queue + queue)); 422 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; 423 } 424 425 CVMX_SYNCWS; 426 cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); 427 } 428} 429 430/* 431 * Allocate queues for the PKO internal ports. 432 * @INTERNAL 433 * 434 */ 435static void __cvmx_pko_queue_alloc_o68(void) 436{ 437 CVMX_PKO_FOR_EACH_PORT_BEGIN { 438 __cvmx_pko_iport_config(XIT_pko_port); 439 } CVMX_PKO_FOR_EACH_PORT_END; 440} 441 442/* 443 * Allocate memory for PKO engines. 444 * 445 * @param engine is the PKO engine ID. 446 * @return # of 2KB-chunks allocated to this PKO engine. 447 */ 448static int __cvmx_pko_memory_per_engine_o68(int engine) 449{ 450 /* CN68XX has 40KB to devide between the engines in 2KB chunks */ 451 int max_engine; 452 int size_per_engine; 453 int size; 454 455 max_engine = __cvmx_helper_cfg_pko_max_engine(); 456 size_per_engine = 40 / 2 / max_engine; 457 458 if (engine >= max_engine) 459 { 460 /* Unused engines get no space */ 461 size = 0; 462 } 463 else if (engine == max_engine - 1) 464 { 465 /* The last engine gets all the space lost by rounding. This means 466 the ILK gets the most space */ 467 size = 40 / 2 - engine * size_per_engine; 468 } 469 else 470 { 471 /* All other engines get the same space */ 472 size = size_per_engine; 473 } 474 475 return size; 476} 477 478/* 479 * Setup one-to-one mapping between PKO iport and eport. 480 * @INTERNAL 481 */ 482static void __cvmx_pko_port_map_o68(void) 483{ 484 int i; 485 int interface, index; 486 cvmx_helper_interface_mode_t mode; 487 cvmx_pko_mem_iport_ptrs_t config; 488 489 /* 490 * Initialize every iport with the invalid eid. 491 */ 492#define CVMX_O68_PKO_INVALID_EID 31 493 config.u64 = 0; 494 config.s.eid = CVMX_O68_PKO_INVALID_EID; 495 for (i = 0; i < CVMX_HELPER_CFG_MAX_PKO_PORT; i++) 496 { 497 config.s.ipid = i; 498 cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 499 } 500 501 /* 502 * Set up PKO_MEM_IPORT_PTRS 503 */ 504 CVMX_PKO_FOR_EACH_PORT_BEGIN { 505 interface = __cvmx_helper_cfg_pko_port_interface(XIT_pko_port); 506 index = __cvmx_helper_cfg_pko_port_index(XIT_pko_port); 507 mode = cvmx_helper_interface_get_mode(interface); 508 509 if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) 510 continue; 511 512 config.s.ipid = XIT_pko_port; 513 config.s.qos_mask = 0xff; 514 config.s.crc = __cvmx_helper_get_has_fcs(interface); 515 config.s.min_pkt = __cvmx_helper_get_pko_padding(interface); 516 config.s.intr = __cvmx_pko_int(interface, index); 517 config.s.eid = __cvmx_helper_cfg_pko_port_eid(XIT_pko_port); 518 config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? index : 519 XIT_pko_port; 520 cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 521 } CVMX_PKO_FOR_EACH_PORT_END; 522} 523 524int __cvmx_pko_get_pipe(int interface, int index) 525{ 526 /* 527 * the loopback ports do not have pipes 528 */ 529 if (cvmx_helper_interface_get_mode(interface) == 530 CVMX_HELPER_INTERFACE_MODE_LOOP) 531 return -1; 532 /* 533 * We use pko_port as the pipe. See __cvmx_pko_port_map_o68(). 534 */ 535 return cvmx_helper_get_pko_port(interface, index); 536} 537 538/* 539 * chip-specific setup 540 * @INTERNAL 541 */ 542static void __cvmx_pko_chip_init(void) 543{ 544 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 545 { 546 __cvmx_pko_port_map_o68(); 547 __cvmx_pko_queue_alloc_o68(); 548 } 549 else 550 { 551 int i; 552 uint64_t priority = 8; 553 554 /* 555 * Initialize queues 556 */ 557 for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) 558 cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, 559 &priority); 560 } 561} 562 563/** 564 * Call before any other calls to initialize the packet 565 * output system. This does chip global config, and should only be 566 * done by one core. 567 */ 568 569void cvmx_pko_initialize_global(void) 570{ 571 cvmx_pko_reg_cmd_buf_t config; 572 int i; 573 574 /* 575 * Set the size of the PKO command buffers to an odd number of 64bit 576 * words. This allows the normal two word send to stay aligned and never 577 * span a command word buffer. 578 */ 579 config.u64 = 0; 580 config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; 581 config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; 582 cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); 583 584 /* 585 * chip-specific setup. 586 */ 587 __cvmx_pko_chip_init(); 588 589 /* 590 * If we aren't using all of the queues optimize PKO's internal memory. 591 */ 592 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || 593 OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) || 594 OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 595 { 596 int num_interfaces; 597 int last_port; 598 int max_queues; 599 600 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 601 max_queues = __cvmx_helper_cfg_pko_max_queue(); 602 else 603 { 604 num_interfaces = cvmx_helper_get_number_of_interfaces(); 605 last_port = cvmx_helper_get_last_ipd_port(num_interfaces-1); 606 max_queues = cvmx_pko_get_base_queue(last_port) + 607 cvmx_pko_get_num_queues(last_port); 608 } 609 610 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 611 { 612 if (max_queues <= 32) 613 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 614 else if (max_queues <= 64) 615 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 616 else 617 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0); 618 } 619 else 620 { 621 if (OCTEON_IS_MODEL(OCTEON_CN68XX) && max_queues <= 32) 622 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 3); 623 else if (max_queues <= 64) 624 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 625 else if (max_queues <= 128) 626 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 627 else 628 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0); 629 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 630 { 631 for (i = 0; i < 2; i++) 632 { 633 cvmx_pko_reg_engine_storagex_t engine_storage; 634 635#define PKO_ASSIGN_ENGINE_STORAGE(index) \ 636 engine_storage.s.engine##index = \ 637 __cvmx_pko_memory_per_engine_o68(16 * i + (index)) 638 639 engine_storage.u64 = 0; 640 PKO_ASSIGN_ENGINE_STORAGE(0); 641 PKO_ASSIGN_ENGINE_STORAGE(1); 642 PKO_ASSIGN_ENGINE_STORAGE(2); 643 PKO_ASSIGN_ENGINE_STORAGE(3); 644 PKO_ASSIGN_ENGINE_STORAGE(4); 645 PKO_ASSIGN_ENGINE_STORAGE(5); 646 PKO_ASSIGN_ENGINE_STORAGE(6); 647 PKO_ASSIGN_ENGINE_STORAGE(7); 648 PKO_ASSIGN_ENGINE_STORAGE(8); 649 PKO_ASSIGN_ENGINE_STORAGE(9); 650 PKO_ASSIGN_ENGINE_STORAGE(10); 651 PKO_ASSIGN_ENGINE_STORAGE(11); 652 PKO_ASSIGN_ENGINE_STORAGE(12); 653 PKO_ASSIGN_ENGINE_STORAGE(13); 654 PKO_ASSIGN_ENGINE_STORAGE(14); 655 PKO_ASSIGN_ENGINE_STORAGE(15); 656 cvmx_write_csr(CVMX_PKO_REG_ENGINE_STORAGEX(i), 657 engine_storage.u64); 658 } 659 } 660 } 661 } 662} 663 664/** 665 * This function does per-core initialization required by the PKO routines. 666 * This must be called on all cores that will do packet output, and must 667 * be called after the FPA has been initialized and filled with pages. 668 * 669 * @return 0 on success 670 * !0 on failure 671 */ 672int cvmx_pko_initialize_local(void) 673{ 674 /* Nothing to do */ 675 return 0; 676} 677#endif 678 679/** 680 * Enables the packet output hardware. It must already be 681 * configured. 682 */ 683void cvmx_pko_enable(void) 684{ 685 cvmx_pko_reg_flags_t flags; 686 687 flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 688 if (flags.s.ena_pko) 689 cvmx_dprintf("Warning: Enabling PKO when PKO already enabled.\n"); 690 691 flags.s.ena_dwb = cvmx_helper_cfg_opt_get(CVMX_HELPER_CFG_OPT_USE_DWB); 692 flags.s.ena_pko = 1; 693 flags.s.store_be =1; /* 694 * always enable big endian for 3-word command. 695 * Does nothing for 2-word. 696 */ 697 cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); 698} 699 700/** 701 * Disables the packet output. Does not affect any configuration. 702 */ 703void cvmx_pko_disable(void) 704{ 705 cvmx_pko_reg_flags_t pko_reg_flags; 706 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 707 pko_reg_flags.s.ena_pko = 0; 708 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 709} 710 711#ifdef CVMX_ENABLE_PKO_FUNCTIONS 712/** 713 * @INTERNAL 714 * Reset the packet output. 715 */ 716static void __cvmx_pko_reset(void) 717{ 718 cvmx_pko_reg_flags_t pko_reg_flags; 719 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 720 pko_reg_flags.s.reset = 1; 721 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 722} 723 724/** 725 * Shutdown and free resources required by packet output. 726 */ 727void cvmx_pko_shutdown(void) 728{ 729 int queue; 730 731 cvmx_pko_disable(); 732 733 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 734 { 735 cvmx_pko_mem_iqueue_ptrs_t config; 736 config.u64 = 0; 737 for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) 738 { 739 config.s.qid = queue; 740 cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); 741 cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 742 } 743 } 744 else 745 { 746 cvmx_pko_mem_queue_ptrs_t config; 747 for (queue=0; queue<CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) 748 { 749 config.u64 = 0; 750 config.s.tail = 1; 751 config.s.index = 0; 752 config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; 753 config.s.queue = queue & 0x7f; 754 config.s.qos_mask = 0; 755 config.s.buf_ptr = 0; 756 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 757 { 758 cvmx_pko_reg_queue_ptrs1_t config1; 759 config1.u64 = 0; 760 config1.s.qid7 = queue >> 7; 761 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 762 } 763 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 764 cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 765 } 766 } 767 768 __cvmx_pko_reset(); 769} 770 771/** 772 * Configure a output port and the associated queues for use. 773 * 774 * @param port Port to configure. 775 * @param base_queue First queue number to associate with this port. 776 * @param num_queues Number of queues to associate with this port 777 * @param priority Array of priority levels for each queue. Values are 778 * allowed to be 0-8. A value of 8 get 8 times the traffic 779 * of a value of 1. A value of 0 indicates that no rounds 780 * will be participated in. These priorities can be changed 781 * on the fly while the pko is enabled. A priority of 9 782 * indicates that static priority should be used. If static 783 * priority is used all queues with static priority must be 784 * contiguous starting at the base_queue, and lower numbered 785 * queues have higher priority than higher numbered queues. 786 * There must be num_queues elements in the array. 787 */ 788cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, 789 uint64_t num_queues, const uint64_t priority[]) 790{ 791 cvmx_pko_status_t result_code; 792 uint64_t queue; 793 cvmx_pko_mem_queue_ptrs_t config; 794 cvmx_pko_reg_queue_ptrs1_t config1; 795 int static_priority_base = -1; 796 int static_priority_end = -1; 797 798 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 799 return CVMX_PKO_SUCCESS; 800 801 if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) && 802 (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) 803 { 804 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", 805 (unsigned long long)port); 806 return CVMX_PKO_INVALID_PORT; 807 } 808 809 if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) 810 { 811 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", 812 (unsigned long long)(base_queue + num_queues)); 813 return CVMX_PKO_INVALID_QUEUE; 814 } 815 816 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 817 { 818 /* 819 * Validate the static queue priority setup and set 820 * static_priority_base and static_priority_end accordingly. 821 */ 822 for (queue = 0; queue < num_queues; queue++) 823 { 824 /* Find first queue of static priority */ 825 if (static_priority_base == -1 && priority[queue] == 826 CVMX_PKO_QUEUE_STATIC_PRIORITY) 827 static_priority_base = queue; 828 /* Find last queue of static priority */ 829 if (static_priority_base != -1 && static_priority_end == -1 && 830 priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && queue) 831 static_priority_end = queue - 1; 832 else if (static_priority_base != -1 && static_priority_end == -1 && 833 queue == num_queues - 1) 834 static_priority_end = queue; /* all queues're static priority */ 835 836 /* 837 * Check to make sure all static priority queues are contiguous. 838 * Also catches some cases of static priorites not starting at 839 * queue 0. 840 */ 841 if (static_priority_end != -1 && (int)queue > static_priority_end && 842 priority[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 843 { 844 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority " 845 "queues aren't contiguous or don't start at base queue. " 846 "q: %d, eq: %d\n", (int)queue, static_priority_end); 847 return CVMX_PKO_INVALID_PRIORITY; 848 } 849 } 850 if (static_priority_base > 0) 851 { 852 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority queues " 853 "don't start at base queue. sq: %d\n", static_priority_base); 854 return CVMX_PKO_INVALID_PRIORITY; 855 } 856 } 857 858 /* 859 * At this point, static_priority_base and static_priority_end are either 860 * both -1, or are valid start/end queue numbers 861 */ 862 863 result_code = CVMX_PKO_SUCCESS; 864 865#ifdef PKO_DEBUG 866 cvmx_dprintf("num queues: %d (%lld,%lld)\n", (int)num_queues, 867 (unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, 868 (unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); 869#endif 870 871 for (queue = 0; queue < num_queues; queue++) 872 { 873 uint64_t *buf_ptr = NULL; 874 875 config1.u64 = 0; 876 config1.s.idx3 = queue >> 3; 877 config1.s.qid7 = (base_queue + queue) >> 7; 878 879 config.u64 = 0; 880 config.s.tail = queue == (num_queues - 1); 881 config.s.index = queue; 882 config.s.port = port; 883 config.s.queue = base_queue + queue; 884 885 config.s.static_p = static_priority_base >= 0; 886 config.s.static_q = (int)queue <= static_priority_end; 887 config.s.s_tail = (int)queue == static_priority_end; 888 /* 889 * Convert the priority into an enable bit field. Try to space the bits 890 * out evenly so the packet don't get grouped up 891 */ 892 switch ((int)priority[queue]) 893 { 894 case 0: config.s.qos_mask = 0x00; break; 895 case 1: config.s.qos_mask = 0x01; break; 896 case 2: config.s.qos_mask = 0x11; break; 897 case 3: config.s.qos_mask = 0x49; break; 898 case 4: config.s.qos_mask = 0x55; break; 899 case 5: config.s.qos_mask = 0x57; break; 900 case 6: config.s.qos_mask = 0x77; break; 901 case 7: config.s.qos_mask = 0x7f; break; 902 case 8: config.s.qos_mask = 0xff; break; 903 case CVMX_PKO_QUEUE_STATIC_PRIORITY: 904 config.s.qos_mask = 0xff; 905 break; 906 default: 907 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid priority %llu\n", 908 (unsigned long long)priority[queue]); 909 config.s.qos_mask = 0xff; 910 result_code = CVMX_PKO_INVALID_PRIORITY; 911 break; 912 } 913 914 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 915 { 916 cvmx_cmd_queue_result_t cmd_res = cvmx_cmd_queue_initialize( 917 CVMX_CMD_QUEUE_PKO(base_queue + queue), 918 CVMX_PKO_MAX_QUEUE_DEPTH, 919 CVMX_FPA_OUTPUT_BUFFER_POOL, 920 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - 921 CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST*8); 922 if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) 923 { 924 switch (cmd_res) 925 { 926 case CVMX_CMD_QUEUE_NO_MEMORY: 927 cvmx_dprintf("ERROR: cvmx_pko_config_port: " 928 "Unable to allocate output buffer.\n"); 929 return(CVMX_PKO_NO_MEMORY); 930 case CVMX_CMD_QUEUE_ALREADY_SETUP: 931 cvmx_dprintf("ERROR: cvmx_pko_config_port: " 932 "Port already setup.\n"); 933 return(CVMX_PKO_PORT_ALREADY_SETUP); 934 case CVMX_CMD_QUEUE_INVALID_PARAM: 935 default: 936 cvmx_dprintf("ERROR: cvmx_pko_config_port: " 937 "Command queue initialization failed.\n"); 938 return(CVMX_PKO_CMD_QUEUE_INIT_ERROR); 939 } 940 } 941 942 buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer( 943 CVMX_CMD_QUEUE_PKO(base_queue + queue)); 944 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); 945 } 946 else 947 config.s.buf_ptr = 0; 948 949 CVMX_SYNCWS; 950 951 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 952 { 953 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 954 } 955 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 956 } 957 958 return result_code; 959} 960 961/** 962 * Rate limit a PKO port to a max packets/sec. This function is only 963 * supported on CN51XX and higher, excluding CN58XX. 964 * 965 * @param port Port to rate limit 966 * @param packets_s Maximum packet/sec 967 * @param burst Maximum number of packets to burst in a row before rate 968 * limiting cuts in. 969 * 970 * @return Zero on success, negative on failure 971 */ 972int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) 973{ 974 cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 975 cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 976 977 pko_mem_port_rate0.u64 = 0; 978 pko_mem_port_rate0.s.pid = port; 979 pko_mem_port_rate0.s.rate_pkt = 980 cvmx_clock_get_rate(CVMX_CLOCK_SCLK) / packets_s / 16; 981 /* No cost per word since we are limited by packets/sec, not bits/sec */ 982 pko_mem_port_rate0.s.rate_word = 0; 983 984 pko_mem_port_rate1.u64 = 0; 985 pko_mem_port_rate1.s.pid = port; 986 pko_mem_port_rate1.s.rate_lim = 987 ((uint64_t)pko_mem_port_rate0.s.rate_pkt * burst) >> 8; 988 989 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 990 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 991 return 0; 992} 993 994/** 995 * Rate limit a PKO port to a max bits/sec. This function is only 996 * supported on CN51XX and higher, excluding CN58XX. 997 * 998 * @param port Port to rate limit 999 * @param bits_s PKO rate limit in bits/sec 1000 * @param burst Maximum number of bits to burst before rate 1001 * limiting cuts in. 1002 * 1003 * @return Zero on success, negative on failure 1004 */ 1005int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) 1006{ 1007 cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 1008 cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 1009 uint64_t clock_rate = cvmx_clock_get_rate(CVMX_CLOCK_SCLK); 1010 uint64_t tokens_per_bit = clock_rate*16 / bits_s; 1011 1012 pko_mem_port_rate0.u64 = 0; 1013 pko_mem_port_rate0.s.pid = port; 1014 /* Each packet has a 12 bytes of interframe gap, an 8 byte preamble, and a 1015 4 byte CRC. These are not included in the per word count. Multiply 1016 by 8 to covert to bits and divide by 256 for limit granularity */ 1017 pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; 1018 /* Each 8 byte word has 64bits */ 1019 pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; 1020 1021 pko_mem_port_rate1.u64 = 0; 1022 pko_mem_port_rate1.s.pid = port; 1023 pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; 1024 1025 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 1026 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 1027 return 0; 1028} 1029 1030#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 1031