1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018-2022 Marvell International Ltd. 4 */ 5 6#include <errno.h> 7#include <log.h> 8#include <time.h> 9#include <linux/delay.h> 10 11#include <mach/cvmx-regs.h> 12#include <mach/cvmx-csr.h> 13#include <mach/cvmx-bootmem.h> 14#include <mach/octeon-model.h> 15#include <mach/cvmx-fuse.h> 16#include <mach/octeon-feature.h> 17#include <mach/cvmx-qlm.h> 18#include <mach/octeon_qlm.h> 19#include <mach/cvmx-pcie.h> 20#include <mach/cvmx-coremask.h> 21 22#include <mach/cvmx-agl-defs.h> 23#include <mach/cvmx-bgxx-defs.h> 24#include <mach/cvmx-ciu-defs.h> 25#include <mach/cvmx-gmxx-defs.h> 26#include <mach/cvmx-gserx-defs.h> 27#include <mach/cvmx-ilk-defs.h> 28#include <mach/cvmx-ipd-defs.h> 29#include <mach/cvmx-pcsx-defs.h> 30#include <mach/cvmx-pcsxx-defs.h> 31#include <mach/cvmx-pki-defs.h> 32#include <mach/cvmx-pko-defs.h> 33#include <mach/cvmx-xcv-defs.h> 34 35#include <mach/cvmx-hwpko.h> 36#include <mach/cvmx-ilk.h> 37#include <mach/cvmx-pki.h> 38#include <mach/cvmx-pko3.h> 39#include <mach/cvmx-pko3-queue.h> 40#include <mach/cvmx-pko3-resources.h> 41 42#include <mach/cvmx-helper.h> 43#include <mach/cvmx-helper-board.h> 44#include <mach/cvmx-helper-cfg.h> 45 46#include <mach/cvmx-helper-bgx.h> 47#include <mach/cvmx-helper-cfg.h> 48#include <mach/cvmx-helper-util.h> 49#include <mach/cvmx-helper-pki.h> 50 51/* Smalles Round-Robin quantum to use +1 */ 52#define CVMX_PKO3_RR_QUANTUM_MIN 0x10 53 54static int debug; /* 1 for basic, 2 for detailed trace */ 55 56struct cvmx_pko3_dq { 57 unsigned dq_count : 6; /* Number of descriptor queues */ 58 unsigned dq_base : 10; /* Descriptor queue start number */ 59#define CVMX_PKO3_SWIZZLE_IPD 0x0 60}; 61 62/* 63 * @INTERNAL 64 * Descriptor Queue to IPD port mapping table. 65 * 66 * This pointer is per-core, contains the virtual address 67 * of a global named block which has 2^12 entries per each 68 * possible node. 69 */ 70struct cvmx_pko3_dq *__cvmx_pko3_dq_table; 71 72int cvmx_pko3_get_queue_base(int ipd_port) 73{ 74 struct cvmx_pko3_dq *dq_table; 75 int ret = -1; 76 unsigned int i; 77 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port); 78 79 /* get per-node table */ 80 if (cvmx_unlikely(!__cvmx_pko3_dq_table)) 81 __cvmx_pko3_dq_table_setup(); 82 83 i = CVMX_PKO3_SWIZZLE_IPD ^ xp.port; 84 85 /* get per-node table */ 86 dq_table = __cvmx_pko3_dq_table + CVMX_PKO3_IPD_NUM_MAX * xp.node; 87 88 if (cvmx_likely(dq_table[i].dq_count > 0)) 89 ret = xp.node << 10 | dq_table[i].dq_base; 90 else if (debug) 91 cvmx_printf("ERROR: %s: no queues for ipd_port=%#x\n", __func__, 92 ipd_port); 93 94 return ret; 95} 96 97int cvmx_pko3_get_queue_num(int ipd_port) 98{ 99 struct cvmx_pko3_dq *dq_table; 100 int ret = -1; 101 unsigned int i; 102 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port); 103 104 /* get per-node table */ 105 if (cvmx_unlikely(!__cvmx_pko3_dq_table)) 106 __cvmx_pko3_dq_table_setup(); 107 108 i = CVMX_PKO3_SWIZZLE_IPD ^ xp.port; 109 110 /* get per-node table */ 111 dq_table = __cvmx_pko3_dq_table + CVMX_PKO3_IPD_NUM_MAX * xp.node; 112 113 if (cvmx_likely(dq_table[i].dq_count > 0)) 114 ret = dq_table[i].dq_count; 115 else if (debug) 116 debug("ERROR: %s: no queues for ipd_port=%#x\n", __func__, 117 ipd_port); 118 119 return ret; 120} 121 122/** 123 * @INTERNAL 124 * 125 * Initialize port/dq table contents 126 */ 127static void __cvmx_pko3_dq_table_init(void *ptr) 128{ 129 unsigned int size = sizeof(struct cvmx_pko3_dq) * 130 CVMX_PKO3_IPD_NUM_MAX * CVMX_MAX_NODES; 131 132 memset(ptr, 0, size); 133} 134 135/** 136 * @INTERNAL 137 * 138 * Find or allocate global port/dq map table 139 * which is a named table, contains entries for 140 * all possible OCI nodes. 141 * 142 * The table global pointer is stored in core-local variable 143 * so that every core will call this function once, on first use. 144 */ 145int __cvmx_pko3_dq_table_setup(void) 146{ 147 void *ptr; 148 149 ptr = cvmx_bootmem_alloc_named_range_once( 150 /* size */ 151 sizeof(struct cvmx_pko3_dq) * CVMX_PKO3_IPD_NUM_MAX * 152 CVMX_MAX_NODES, 153 /* min_addr, max_addr, align */ 154 0ull, 0ull, sizeof(struct cvmx_pko3_dq), 155 /* name */ 156 "cvmx_pko3_global_dq_table", __cvmx_pko3_dq_table_init); 157 158 if (debug) 159 debug("%s: dq_table_ptr=%p\n", __func__, ptr); 160 161 if (!ptr) 162 return -1; 163 164 __cvmx_pko3_dq_table = ptr; 165 return 0; 166} 167 168/* 169 * @INTERNAL 170 * Register a range of Descriptor Queues with an interface port 171 * 172 * This function populates the DQ-to-IPD translation table 173 * used by the application to retrieve the DQ range (typically ordered 174 * by priority) for a given IPD-port, which is either a physical port, 175 * or a channel on a channelized interface (i.e. ILK). 176 * 177 * @param xiface is the physical interface number 178 * @param index is either a physical port on an interface 179 * or a channel of an ILK interface 180 * @param dq_base is the first Descriptor Queue number in a consecutive range 181 * @param dq_count is the number of consecutive Descriptor Queues leading 182 * the same channel or port. 183 * 184 * Only a consecutive range of Descriptor Queues can be associated with any 185 * given channel/port, and usually they are ordered from most to least 186 * in terms of scheduling priority. 187 * 188 * Note: thus function only populates the node-local translation table. 189 * NOTE: This function would be cleaner if it had a single ipd_port argument 190 * 191 * @returns 0 on success, -1 on failure. 192 */ 193int __cvmx_pko3_ipd_dq_register(int xiface, int index, unsigned int dq_base, 194 unsigned int dq_count) 195{ 196 struct cvmx_pko3_dq *dq_table; 197 int ipd_port; 198 unsigned int i; 199 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 200 struct cvmx_xport xp; 201 202 if (__cvmx_helper_xiface_is_null(xiface)) { 203 ipd_port = cvmx_helper_node_to_ipd_port(xi.node, 204 CVMX_PKO3_IPD_PORT_NULL); 205 } else { 206 int p; 207 208 p = cvmx_helper_get_ipd_port(xiface, index); 209 if (p < 0) { 210 cvmx_printf("ERROR: %s: xiface %#x has no IPD port\n", 211 __func__, xiface); 212 return -1; 213 } 214 ipd_port = p; 215 } 216 217 xp = cvmx_helper_ipd_port_to_xport(ipd_port); 218 219 i = CVMX_PKO3_SWIZZLE_IPD ^ xp.port; 220 221 /* get per-node table */ 222 if (!__cvmx_pko3_dq_table) 223 __cvmx_pko3_dq_table_setup(); 224 225 dq_table = __cvmx_pko3_dq_table + CVMX_PKO3_IPD_NUM_MAX * xi.node; 226 227 if (debug) 228 debug("%s: ipd_port=%#x ix=%#x dq %u cnt %u\n", __func__, 229 ipd_port, i, dq_base, dq_count); 230 231 /* Check the IPD port has not already been configured */ 232 if (dq_table[i].dq_count > 0) { 233 cvmx_printf("%s: ERROR: IPD %#x already registered\n", __func__, 234 ipd_port); 235 return -1; 236 } 237 238 /* Store DQ# range in the queue lookup table */ 239 dq_table[i].dq_base = dq_base; 240 dq_table[i].dq_count = dq_count; 241 242 return 0; 243} 244 245/* 246 * @INTERNAL 247 * Convert normal CHAN_E (i.e. IPD port) value to compressed channel form 248 * that is used to populate PKO_LUT. 249 * 250 * Note: This code may be model specific. 251 */ 252static int cvmx_pko3_chan_2_xchan(uint16_t ipd_port) 253{ 254 u16 xchan; 255 u8 off; 256 static const u8 *xchan_base; 257 static const u8 xchan_base_cn78xx[16] = { 258 /* IPD 0x000 */ 0x3c0 >> 4, /* LBK */ 259 /* IPD 0x100 */ 0x380 >> 4, /* DPI */ 260 /* IPD 0x200 */ 0xfff >> 4, /* not used */ 261 /* IPD 0x300 */ 0xfff >> 4, /* not used */ 262 /* IPD 0x400 */ 0x000 >> 4, /* ILK0 */ 263 /* IPD 0x500 */ 0x100 >> 4, /* ILK1 */ 264 /* IPD 0x600 */ 0xfff >> 4, /* not used */ 265 /* IPD 0x700 */ 0xfff >> 4, /* not used */ 266 /* IPD 0x800 */ 0x200 >> 4, /* BGX0 */ 267 /* IPD 0x900 */ 0x240 >> 4, /* BGX1 */ 268 /* IPD 0xa00 */ 0x280 >> 4, /* BGX2 */ 269 /* IPD 0xb00 */ 0x2c0 >> 4, /* BGX3 */ 270 /* IPD 0xc00 */ 0x300 >> 4, /* BGX4 */ 271 /* IPD 0xd00 */ 0x340 >> 4, /* BGX5 */ 272 /* IPD 0xe00 */ 0xfff >> 4, /* not used */ 273 /* IPD 0xf00 */ 0xfff >> 4 /* not used */ 274 }; 275 static const u8 xchan_base_cn73xx[16] = { 276 /* IPD 0x000 */ 0x0c0 >> 4, /* LBK */ 277 /* IPD 0x100 */ 0x100 >> 4, /* DPI */ 278 /* IPD 0x200 */ 0xfff >> 4, /* not used */ 279 /* IPD 0x300 */ 0xfff >> 4, /* not used */ 280 /* IPD 0x400 */ 0xfff >> 4, /* not used */ 281 /* IPD 0x500 */ 0xfff >> 4, /* not used */ 282 /* IPD 0x600 */ 0xfff >> 4, /* not used */ 283 /* IPD 0x700 */ 0xfff >> 4, /* not used */ 284 /* IPD 0x800 */ 0x000 >> 4, /* BGX0 */ 285 /* IPD 0x900 */ 0x040 >> 4, /* BGX1 */ 286 /* IPD 0xa00 */ 0x080 >> 4, /* BGX2 */ 287 /* IPD 0xb00 */ 0xfff >> 4, /* not used */ 288 /* IPD 0xc00 */ 0xfff >> 4, /* not used */ 289 /* IPD 0xd00 */ 0xfff >> 4, /* not used */ 290 /* IPD 0xe00 */ 0xfff >> 4, /* not used */ 291 /* IPD 0xf00 */ 0xfff >> 4 /* not used */ 292 }; 293 static const u8 xchan_base_cn75xx[16] = { 294 /* IPD 0x000 */ 0x040 >> 4, /* LBK */ 295 /* IPD 0x100 */ 0x080 >> 4, /* DPI */ 296 /* IPD 0x200 */ 0xeee >> 4, /* SRIO0 noop */ 297 /* IPD 0x300 */ 0xfff >> 4, /* not used */ 298 /* IPD 0x400 */ 0xfff >> 4, /* not used */ 299 /* IPD 0x500 */ 0xfff >> 4, /* not used */ 300 /* IPD 0x600 */ 0xfff >> 4, /* not used */ 301 /* IPD 0x700 */ 0xfff >> 4, /* not used */ 302 /* IPD 0x800 */ 0x000 >> 4, /* BGX0 */ 303 /* IPD 0x900 */ 0xfff >> 4, /* not used */ 304 /* IPD 0xa00 */ 0xfff >> 4, /* not used */ 305 /* IPD 0xb00 */ 0xfff >> 4, /* not used */ 306 /* IPD 0xc00 */ 0xfff >> 4, /* not used */ 307 /* IPD 0xd00 */ 0xfff >> 4, /* not used */ 308 /* IPD 0xe00 */ 0xfff >> 4, /* not used */ 309 /* IPD 0xf00 */ 0xfff >> 4 /* not used */ 310 }; 311 312 if (OCTEON_IS_MODEL(OCTEON_CN73XX)) 313 xchan_base = xchan_base_cn73xx; 314 if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) 315 xchan_base = xchan_base_cn75xx; 316 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 317 xchan_base = xchan_base_cn78xx; 318 319 if (!xchan_base) 320 return -1; 321 322 xchan = ipd_port >> 8; 323 324 /* ILKx, DPI has 8 bits logical channels, others just 6 */ 325 if (((xchan & 0xfe) == 0x04) || xchan == 0x01) 326 off = ipd_port & 0xff; 327 else 328 off = ipd_port & 0x3f; 329 330 xchan = xchan_base[xchan & 0xf]; 331 332 if (xchan == 0xff) 333 return -1; /* Invalid IPD_PORT */ 334 else if (xchan == 0xee) 335 return -2; /* LUT not used */ 336 else 337 return (xchan << 4) | off; 338} 339 340/* 341 * Map channel number in PKO 342 * 343 * @param node is to specify the node to which this configuration is applied. 344 * @param pq_num specifies the Port Queue (i.e. L1) queue number. 345 * @param l2_l3_q_num specifies L2/L3 queue number. 346 * @param channel specifies the channel number to map to the queue. 347 * 348 * The channel assignment applies to L2 or L3 Shaper Queues depending 349 * on the setting of channel credit level. 350 * 351 * @return returns none. 352 */ 353void cvmx_pko3_map_channel(unsigned int node, unsigned int pq_num, 354 unsigned int l2_l3_q_num, uint16_t channel) 355{ 356 union cvmx_pko_l3_l2_sqx_channel sqx_channel; 357 cvmx_pko_lutx_t lutx; 358 int xchan; 359 360 sqx_channel.u64 = 361 csr_rd_node(node, CVMX_PKO_L3_L2_SQX_CHANNEL(l2_l3_q_num)); 362 363 sqx_channel.s.cc_channel = channel; 364 365 csr_wr_node(node, CVMX_PKO_L3_L2_SQX_CHANNEL(l2_l3_q_num), 366 sqx_channel.u64); 367 368 /* Convert CHAN_E into compressed channel */ 369 xchan = cvmx_pko3_chan_2_xchan(channel); 370 371 if (debug) 372 debug("%s: ipd_port=%#x xchan=%#x\n", __func__, channel, xchan); 373 374 if (xchan < 0) { 375 if (xchan == -1) 376 cvmx_printf("%s: ERROR: channel %#x not recognized\n", 377 __func__, channel); 378 return; 379 } 380 381 lutx.u64 = 0; 382 lutx.s.valid = 1; 383 lutx.s.pq_idx = pq_num; 384 lutx.s.queue_number = l2_l3_q_num; 385 386 csr_wr_node(node, CVMX_PKO_LUTX(xchan), lutx.u64); 387 388 if (debug) 389 debug("%s: channel %#x (compressed=%#x) mapped L2/L3 SQ=%u, PQ=%u\n", 390 __func__, channel, xchan, l2_l3_q_num, pq_num); 391} 392 393/* 394 * @INTERNAL 395 * This function configures port queue scheduling and topology parameters 396 * in hardware. 397 * 398 * @param node is to specify the node to which this configuration is applied. 399 * @param port_queue is the port queue number to be configured. 400 * @param mac_num is the mac number of the mac that will be tied to this port_queue. 401 */ 402static void cvmx_pko_configure_port_queue(int node, int port_queue, int mac_num) 403{ 404 cvmx_pko_l1_sqx_topology_t pko_l1_topology; 405 cvmx_pko_l1_sqx_shape_t pko_l1_shape; 406 cvmx_pko_l1_sqx_link_t pko_l1_link; 407 408 pko_l1_topology.u64 = 0; 409 pko_l1_topology.s.link = mac_num; 410 csr_wr_node(node, CVMX_PKO_L1_SQX_TOPOLOGY(port_queue), 411 pko_l1_topology.u64); 412 413 pko_l1_shape.u64 = 0; 414 pko_l1_shape.s.link = mac_num; 415 csr_wr_node(node, CVMX_PKO_L1_SQX_SHAPE(port_queue), pko_l1_shape.u64); 416 417 pko_l1_link.u64 = 0; 418 pko_l1_link.s.link = mac_num; 419 csr_wr_node(node, CVMX_PKO_L1_SQX_LINK(port_queue), pko_l1_link.u64); 420} 421 422/* 423 * @INTERNAL 424 * This function configures level 2 queues scheduling and topology parameters 425 * in hardware. 426 * 427 * @param node is to specify the node to which this configuration is applied. 428 * @param queue is the level3 queue number to be configured. 429 * @param parent_queue is the parent queue at next level for this l3 queue. 430 * @param prio is this queue's priority in parent's scheduler. 431 * @param rr_quantum is this queue's round robin quantum value. 432 * @param child_base is the first child queue number in the static prioriy children. 433 * @param child_rr_prio is the round robin children priority. 434 */ 435static void cvmx_pko_configure_l2_queue(int node, int queue, int parent_queue, 436 int prio, int rr_quantum, 437 int child_base, int child_rr_prio) 438{ 439 cvmx_pko_l2_sqx_schedule_t pko_sq_sched; 440 cvmx_pko_l2_sqx_topology_t pko_child_topology; 441 cvmx_pko_l1_sqx_topology_t pko_parent_topology; 442 443 /* parent topology configuration */ 444 pko_parent_topology.u64 = 445 csr_rd_node(node, CVMX_PKO_L1_SQX_TOPOLOGY(parent_queue)); 446 pko_parent_topology.s.prio_anchor = child_base; 447 pko_parent_topology.s.rr_prio = child_rr_prio; 448 csr_wr_node(node, CVMX_PKO_L1_SQX_TOPOLOGY(parent_queue), 449 pko_parent_topology.u64); 450 451 if (debug > 1) 452 debug("CVMX_PKO_L1_SQX_TOPOLOGY(%u): PRIO_ANCHOR=%u PARENT=%u\n", 453 parent_queue, pko_parent_topology.s.prio_anchor, 454 pko_parent_topology.s.link); 455 456 /* scheduler configuration for this sq in the parent queue */ 457 pko_sq_sched.u64 = 0; 458 pko_sq_sched.s.prio = prio; 459 pko_sq_sched.s.rr_quantum = rr_quantum; 460 csr_wr_node(node, CVMX_PKO_L2_SQX_SCHEDULE(queue), pko_sq_sched.u64); 461 462 /* child topology configuration */ 463 pko_child_topology.u64 = 0; 464 pko_child_topology.s.parent = parent_queue; 465 csr_wr_node(node, CVMX_PKO_L2_SQX_TOPOLOGY(queue), 466 pko_child_topology.u64); 467} 468 469/* 470 * @INTERNAL 471 * This function configures level 3 queues scheduling and topology parameters 472 * in hardware. 473 * 474 * @param node is to specify the node to which this configuration is applied. 475 * @param queue is the level3 queue number to be configured. 476 * @param parent_queue is the parent queue at next level for this l3 queue. 477 * @param prio is this queue's priority in parent's scheduler. 478 * @param rr_quantum is this queue's round robin quantum value. 479 * @param child_base is the first child queue number in the static prioriy children. 480 * @param child_rr_prio is the round robin children priority. 481 */ 482static void cvmx_pko_configure_l3_queue(int node, int queue, int parent_queue, 483 int prio, int rr_quantum, 484 int child_base, int child_rr_prio) 485{ 486 cvmx_pko_l3_sqx_schedule_t pko_sq_sched; 487 cvmx_pko_l3_sqx_topology_t pko_child_topology; 488 cvmx_pko_l2_sqx_topology_t pko_parent_topology; 489 490 /* parent topology configuration */ 491 pko_parent_topology.u64 = 492 csr_rd_node(node, CVMX_PKO_L2_SQX_TOPOLOGY(parent_queue)); 493 pko_parent_topology.s.prio_anchor = child_base; 494 pko_parent_topology.s.rr_prio = child_rr_prio; 495 csr_wr_node(node, CVMX_PKO_L2_SQX_TOPOLOGY(parent_queue), 496 pko_parent_topology.u64); 497 498 if (debug > 1) 499 debug("CVMX_PKO_L2_SQX_TOPOLOGY(%u): PRIO_ANCHOR=%u PARENT=%u\n", 500 parent_queue, pko_parent_topology.s.prio_anchor, 501 pko_parent_topology.s.parent); 502 503 /* scheduler configuration for this sq in the parent queue */ 504 pko_sq_sched.u64 = 0; 505 pko_sq_sched.s.prio = prio; 506 pko_sq_sched.s.rr_quantum = rr_quantum; 507 csr_wr_node(node, CVMX_PKO_L3_SQX_SCHEDULE(queue), pko_sq_sched.u64); 508 509 /* child topology configuration */ 510 pko_child_topology.u64 = 0; 511 pko_child_topology.s.parent = parent_queue; 512 csr_wr_node(node, CVMX_PKO_L3_SQX_TOPOLOGY(queue), 513 pko_child_topology.u64); 514} 515 516/* 517 * @INTERNAL 518 * This function configures level 4 queues scheduling and topology parameters 519 * in hardware. 520 * 521 * @param node is to specify the node to which this configuration is applied. 522 * @param queue is the level4 queue number to be configured. 523 * @param parent_queue is the parent queue at next level for this l4 queue. 524 * @param prio is this queue's priority in parent's scheduler. 525 * @param rr_quantum is this queue's round robin quantum value. 526 * @param child_base is the first child queue number in the static prioriy children. 527 * @param child_rr_prio is the round robin children priority. 528 */ 529static void cvmx_pko_configure_l4_queue(int node, int queue, int parent_queue, 530 int prio, int rr_quantum, 531 int child_base, int child_rr_prio) 532{ 533 cvmx_pko_l4_sqx_schedule_t pko_sq_sched; 534 cvmx_pko_l4_sqx_topology_t pko_child_topology; 535 cvmx_pko_l3_sqx_topology_t pko_parent_topology; 536 537 /* parent topology configuration */ 538 pko_parent_topology.u64 = 539 csr_rd_node(node, CVMX_PKO_L3_SQX_TOPOLOGY(parent_queue)); 540 pko_parent_topology.s.prio_anchor = child_base; 541 pko_parent_topology.s.rr_prio = child_rr_prio; 542 csr_wr_node(node, CVMX_PKO_L3_SQX_TOPOLOGY(parent_queue), 543 pko_parent_topology.u64); 544 545 if (debug > 1) 546 debug("CVMX_PKO_L3_SQX_TOPOLOGY(%u): PRIO_ANCHOR=%u PARENT=%u\n", 547 parent_queue, pko_parent_topology.s.prio_anchor, 548 pko_parent_topology.s.parent); 549 550 /* scheduler configuration for this sq in the parent queue */ 551 pko_sq_sched.u64 = 0; 552 pko_sq_sched.s.prio = prio; 553 pko_sq_sched.s.rr_quantum = rr_quantum; 554 csr_wr_node(node, CVMX_PKO_L4_SQX_SCHEDULE(queue), pko_sq_sched.u64); 555 556 /* topology configuration */ 557 pko_child_topology.u64 = 0; 558 pko_child_topology.s.parent = parent_queue; 559 csr_wr_node(node, CVMX_PKO_L4_SQX_TOPOLOGY(queue), 560 pko_child_topology.u64); 561} 562 563/* 564 * @INTERNAL 565 * This function configures level 5 queues scheduling and topology parameters 566 * in hardware. 567 * 568 * @param node is to specify the node to which this configuration is applied. 569 * @param queue is the level5 queue number to be configured. 570 * @param parent_queue is the parent queue at next level for this l5 queue. 571 * @param prio is this queue's priority in parent's scheduler. 572 * @param rr_quantum is this queue's round robin quantum value. 573 * @param child_base is the first child queue number in the static prioriy children. 574 * @param child_rr_prio is the round robin children priority. 575 */ 576static void cvmx_pko_configure_l5_queue(int node, int queue, int parent_queue, 577 int prio, int rr_quantum, 578 int child_base, int child_rr_prio) 579{ 580 cvmx_pko_l5_sqx_schedule_t pko_sq_sched; 581 cvmx_pko_l4_sqx_topology_t pko_parent_topology; 582 cvmx_pko_l5_sqx_topology_t pko_child_topology; 583 584 /* parent topology configuration */ 585 pko_parent_topology.u64 = 586 csr_rd_node(node, CVMX_PKO_L4_SQX_TOPOLOGY(parent_queue)); 587 pko_parent_topology.s.prio_anchor = child_base; 588 pko_parent_topology.s.rr_prio = child_rr_prio; 589 csr_wr_node(node, CVMX_PKO_L4_SQX_TOPOLOGY(parent_queue), 590 pko_parent_topology.u64); 591 592 if (debug > 1) 593 debug("CVMX_PKO_L4_SQX_TOPOLOGY(%u): PRIO_ANCHOR=%u PARENT=%u\n", 594 parent_queue, pko_parent_topology.s.prio_anchor, 595 pko_parent_topology.s.parent); 596 597 /* scheduler configuration for this sq in the parent queue */ 598 pko_sq_sched.u64 = 0; 599 pko_sq_sched.s.prio = prio; 600 pko_sq_sched.s.rr_quantum = rr_quantum; 601 csr_wr_node(node, CVMX_PKO_L5_SQX_SCHEDULE(queue), pko_sq_sched.u64); 602 603 /* topology configuration */ 604 pko_child_topology.u64 = 0; 605 pko_child_topology.s.parent = parent_queue; 606 csr_wr_node(node, CVMX_PKO_L5_SQX_TOPOLOGY(queue), 607 pko_child_topology.u64); 608} 609 610/* 611 * @INTERNAL 612 * This function configures descriptor queues scheduling and topology parameters 613 * in hardware. 614 * 615 * @param node is to specify the node to which this configuration is applied. 616 * @param dq is the descriptor queue number to be configured. 617 * @param parent_queue is the parent queue at next level for this dq. 618 * @param prio is this queue's priority in parent's scheduler. 619 * @param rr_quantum is this queue's round robin quantum value. 620 * @param child_base is the first child queue number in the static prioriy children. 621 * @param child_rr_prio is the round robin children priority. 622 */ 623static void cvmx_pko_configure_dq(int node, int dq, int parent_queue, int prio, 624 int rr_quantum, int child_base, 625 int child_rr_prio) 626{ 627 cvmx_pko_dqx_schedule_t pko_dq_sched; 628 cvmx_pko_dqx_topology_t pko_dq_topology; 629 cvmx_pko_l5_sqx_topology_t pko_parent_topology; 630 cvmx_pko_dqx_wm_ctl_t pko_dq_wm_ctl; 631 unsigned long long parent_topology_reg; 632 char lvl; 633 634 if (debug) 635 debug("%s: dq %u parent %u child_base %u\n", __func__, dq, 636 parent_queue, child_base); 637 638 if (__cvmx_pko3_sq_lvl_max() == CVMX_PKO_L5_QUEUES) { 639 parent_topology_reg = CVMX_PKO_L5_SQX_TOPOLOGY(parent_queue); 640 lvl = 5; 641 } else if (__cvmx_pko3_sq_lvl_max() == CVMX_PKO_L3_QUEUES) { 642 parent_topology_reg = CVMX_PKO_L3_SQX_TOPOLOGY(parent_queue); 643 lvl = 3; 644 } else { 645 return; 646 } 647 648 if (debug) 649 debug("%s: parent_topology_reg=%#llx\n", __func__, 650 parent_topology_reg); 651 652 /* parent topology configuration */ 653 pko_parent_topology.u64 = csr_rd_node(node, parent_topology_reg); 654 pko_parent_topology.s.prio_anchor = child_base; 655 pko_parent_topology.s.rr_prio = child_rr_prio; 656 csr_wr_node(node, parent_topology_reg, pko_parent_topology.u64); 657 658 if (debug > 1) 659 debug("CVMX_PKO_L%d_SQX_TOPOLOGY(%u): PRIO_ANCHOR=%u PARENT=%u\n", 660 lvl, parent_queue, pko_parent_topology.s.prio_anchor, 661 pko_parent_topology.s.parent); 662 663 /* scheduler configuration for this dq in the parent queue */ 664 pko_dq_sched.u64 = 0; 665 pko_dq_sched.s.prio = prio; 666 pko_dq_sched.s.rr_quantum = rr_quantum; 667 csr_wr_node(node, CVMX_PKO_DQX_SCHEDULE(dq), pko_dq_sched.u64); 668 669 /* topology configuration */ 670 pko_dq_topology.u64 = 0; 671 pko_dq_topology.s.parent = parent_queue; 672 csr_wr_node(node, CVMX_PKO_DQX_TOPOLOGY(dq), pko_dq_topology.u64); 673 674 /* configure for counting packets, not bytes at this level */ 675 pko_dq_wm_ctl.u64 = 0; 676 pko_dq_wm_ctl.s.kind = 1; 677 pko_dq_wm_ctl.s.enable = 0; 678 csr_wr_node(node, CVMX_PKO_DQX_WM_CTL(dq), pko_dq_wm_ctl.u64); 679 680 if (debug > 1) { 681 pko_dq_sched.u64 = csr_rd_node(node, CVMX_PKO_DQX_SCHEDULE(dq)); 682 pko_dq_topology.u64 = 683 csr_rd_node(node, CVMX_PKO_DQX_TOPOLOGY(dq)); 684 debug("CVMX_PKO_DQX_TOPOLOGY(%u)PARENT=%u CVMX_PKO_DQX_SCHEDULE(%u) PRIO=%u Q=%u\n", 685 dq, pko_dq_topology.s.parent, dq, pko_dq_sched.s.prio, 686 pko_dq_sched.s.rr_quantum); 687 } 688} 689 690/* 691 * @INTERNAL 692 * The following structure selects the Scheduling Queue configuration 693 * routine for each of the supported levels. 694 * The initial content of the table will be setup in accordance 695 * to the specific SoC model and its implemented resources 696 */ 697struct pko3_cfg_tab_s { 698 /* function pointer for to configure the given level, last=DQ */ 699 struct { 700 u8 parent_level; 701 void (*cfg_sq_func)(int node, int queue, int parent_queue, 702 int prio, int rr_quantum, int child_base, 703 int child_rr_prio); 704 //XXX for debugging exagerated size 705 } lvl[256]; 706}; 707 708static const struct pko3_cfg_tab_s pko3_cn78xx_cfg = { 709 { [CVMX_PKO_L2_QUEUES] = { CVMX_PKO_PORT_QUEUES, 710 cvmx_pko_configure_l2_queue }, 711 [CVMX_PKO_L3_QUEUES] = { CVMX_PKO_L2_QUEUES, 712 cvmx_pko_configure_l3_queue }, 713 [CVMX_PKO_L4_QUEUES] = { CVMX_PKO_L3_QUEUES, 714 cvmx_pko_configure_l4_queue }, 715 [CVMX_PKO_L5_QUEUES] = { CVMX_PKO_L4_QUEUES, 716 cvmx_pko_configure_l5_queue }, 717 [CVMX_PKO_DESCR_QUEUES] = { CVMX_PKO_L5_QUEUES, 718 cvmx_pko_configure_dq } } 719}; 720 721static const struct pko3_cfg_tab_s pko3_cn73xx_cfg = { 722 { [CVMX_PKO_L2_QUEUES] = { CVMX_PKO_PORT_QUEUES, 723 cvmx_pko_configure_l2_queue }, 724 [CVMX_PKO_L3_QUEUES] = { CVMX_PKO_L2_QUEUES, 725 cvmx_pko_configure_l3_queue }, 726 [CVMX_PKO_DESCR_QUEUES] = { CVMX_PKO_L3_QUEUES, 727 cvmx_pko_configure_dq } } 728}; 729 730/* 731 * Configure Port Queue and its children Scheduler Queue 732 * 733 * Port Queues (a.k.a L1) are assigned 1-to-1 to MACs. 734 * L2 Scheduler Queues are used for specifying channels, and thus there 735 * could be multiple L2 SQs attached to a single L1 PQ, either in a 736 * fair round-robin scheduling, or with static and/or round-robin priorities. 737 * 738 * @param node on which to operate 739 * @param mac_num is the LMAC number to that is associated with the Port Queue, 740 * @param pq_num is the number of the L1 PQ attached to the MAC 741 * 742 * @returns 0 on success, -1 on failure. 743 */ 744int cvmx_pko3_pq_config(unsigned int node, unsigned int mac_num, 745 unsigned int pq_num) 746{ 747 char b1[10]; 748 749 if (debug) 750 debug("%s: MAC%u -> %s\n", __func__, mac_num, 751 __cvmx_pko3_sq_str(b1, CVMX_PKO_PORT_QUEUES, pq_num)); 752 753 cvmx_pko_configure_port_queue(node, pq_num, mac_num); 754 755 return 0; 756} 757 758/* 759 * Configure L3 through L5 Scheduler Queues and Descriptor Queues 760 * 761 * The Scheduler Queues in Levels 3 to 5 and Descriptor Queues are 762 * configured one-to-one or many-to-one to a single parent Scheduler 763 * Queues. The level of the parent SQ is specified in an argument, 764 * as well as the number of children to attach to the specific parent. 765 * The children can have fair round-robin or priority-based scheduling 766 * when multiple children are assigned a single parent. 767 * 768 * @param node on which to operate 769 * @param child_level is the level of the child queue 770 * @param parent_queue is the number of the parent Scheduler Queue 771 * @param child_base is the number of the first child SQ or DQ to assign to 772 * @param child_count is the number of consecutive children to assign 773 * @param stat_prio_count is the priority setting for the children L2 SQs 774 * 775 * If <stat_prio_count> is -1, the Ln children will have equal Round-Robin 776 * relationship with eachother. If <stat_prio_count> is 0, all Ln children 777 * will be arranged in Weighted-Round-Robin, with the first having the most 778 * precedence. If <stat_prio_count> is between 1 and 8, it indicates how 779 * many children will have static priority settings (with the first having 780 * the most precedence), with the remaining Ln children having WRR scheduling. 781 * 782 * @returns 0 on success, -1 on failure. 783 * 784 * Note: this function supports the configuration of node-local unit. 785 */ 786int cvmx_pko3_sq_config_children(unsigned int node, 787 enum cvmx_pko3_level_e child_level, 788 unsigned int parent_queue, 789 unsigned int child_base, 790 unsigned int child_count, int stat_prio_count) 791{ 792 enum cvmx_pko3_level_e parent_level; 793 unsigned int num_elem = 0; 794 unsigned int rr_quantum, rr_count; 795 unsigned int child, prio, rr_prio; 796 const struct pko3_cfg_tab_s *cfg_tbl = NULL; 797 char b1[10], b2[10]; 798 799 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) { 800 num_elem = NUM_ELEMENTS(pko3_cn78xx_cfg.lvl); 801 cfg_tbl = &pko3_cn78xx_cfg; 802 } 803 if (OCTEON_IS_MODEL(OCTEON_CN73XX) || OCTEON_IS_MODEL(OCTEON_CNF75XX)) { 804 num_elem = NUM_ELEMENTS(pko3_cn73xx_cfg.lvl); 805 cfg_tbl = &pko3_cn73xx_cfg; 806 } 807 808 if (!cfg_tbl || child_level >= num_elem) { 809 cvmx_printf("ERROR: %s: model or level %#x invalid\n", __func__, 810 child_level); 811 return -1; 812 } 813 814 parent_level = cfg_tbl->lvl[child_level].parent_level; 815 816 if (!cfg_tbl->lvl[child_level].cfg_sq_func || 817 cfg_tbl->lvl[child_level].parent_level == 0) { 818 cvmx_printf("ERROR: %s: queue level %#x invalid\n", __func__, 819 child_level); 820 return -1; 821 } 822 823 /* First static priority is 0 - top precedence */ 824 prio = 0; 825 826 if (stat_prio_count > (signed int)child_count) 827 stat_prio_count = child_count; 828 829 /* Valid PRIO field is 0..9, limit maximum static priorities */ 830 if (stat_prio_count > 9) 831 stat_prio_count = 9; 832 833 /* Special case of a single child */ 834 if (child_count == 1) { 835 rr_count = 0; 836 rr_prio = 0xF; 837 /* Special case for Fair-RR */ 838 } else if (stat_prio_count < 0) { 839 rr_count = child_count; 840 rr_prio = 0; 841 } else { 842 rr_count = child_count - stat_prio_count; 843 rr_prio = stat_prio_count; 844 } 845 846 /* Compute highest RR_QUANTUM */ 847 if (stat_prio_count > 0) 848 rr_quantum = CVMX_PKO3_RR_QUANTUM_MIN * rr_count; 849 else 850 rr_quantum = CVMX_PKO3_RR_QUANTUM_MIN; 851 852 if (debug) 853 debug("%s: Parent %s child_base %u rr_pri %u\n", __func__, 854 __cvmx_pko3_sq_str(b1, parent_level, parent_queue), 855 child_base, rr_prio); 856 857 /* Parent is configured with child */ 858 859 for (child = child_base; child < (child_base + child_count); child++) { 860 if (debug) 861 debug("%s: Child %s of %s prio %u rr_quantum %#x\n", 862 __func__, 863 __cvmx_pko3_sq_str(b1, child_level, child), 864 __cvmx_pko3_sq_str(b2, parent_level, 865 parent_queue), 866 prio, rr_quantum); 867 868 cfg_tbl->lvl[child_level].cfg_sq_func(node, child, parent_queue, 869 prio, rr_quantum, 870 child_base, rr_prio); 871 872 if (prio < rr_prio) 873 prio++; 874 else if (stat_prio_count > 0) 875 rr_quantum -= CVMX_PKO3_RR_QUANTUM_MIN; 876 } /* for child */ 877 878 return 0; 879} 880