0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include <asm/octeon/octeon.h>
0033
0034 #include <asm/octeon/cvmx-config.h>
0035 #include <asm/octeon/cvmx-pko.h>
0036 #include <asm/octeon/cvmx-helper.h>
0037
0038
0039
0040
0041
0042 static int __cvmx_pko_int(int interface, int index)
0043 {
0044 switch (interface) {
0045 case 0:
0046 return index;
0047 case 1:
0048 return 4;
0049 case 2:
0050 return index + 0x08;
0051 case 3:
0052 return index + 0x0c;
0053 case 4:
0054 return index + 0x10;
0055 case 5:
0056 return 0x1c;
0057 case 6:
0058 return 0x1d;
0059 case 7:
0060 return 0x1e;
0061 case 8:
0062 return 0x1f;
0063 default:
0064 return -1;
0065 }
0066 }
0067
0068 static void __cvmx_pko_iport_config(int pko_port)
0069 {
0070 int queue;
0071 const int num_queues = 1;
0072 const int base_queue = pko_port;
0073 const int static_priority_end = 1;
0074 const int static_priority_base = 1;
0075
0076 for (queue = 0; queue < num_queues; queue++) {
0077 union cvmx_pko_mem_iqueue_ptrs config;
0078 cvmx_cmd_queue_result_t cmd_res;
0079 uint64_t *buf_ptr;
0080
0081 config.u64 = 0;
0082 config.s.index = queue;
0083 config.s.qid = base_queue + queue;
0084 config.s.ipid = pko_port;
0085 config.s.tail = (queue == (num_queues - 1));
0086 config.s.s_tail = (queue == static_priority_end);
0087 config.s.static_p = (static_priority_base >= 0);
0088 config.s.static_q = (queue <= static_priority_end);
0089 config.s.qos_mask = 0xff;
0090
0091 cmd_res = cvmx_cmd_queue_initialize(
0092 CVMX_CMD_QUEUE_PKO(base_queue + queue),
0093 CVMX_PKO_MAX_QUEUE_DEPTH,
0094 CVMX_FPA_OUTPUT_BUFFER_POOL,
0095 (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE -
0096 CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8));
0097
0098 WARN(cmd_res,
0099 "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n",
0100 __func__, (int)cmd_res, pko_port, base_queue,
0101 num_queues, queue);
0102
0103 buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer(
0104 CVMX_CMD_QUEUE_PKO(base_queue + queue));
0105 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7;
0106 CVMX_SYNCWS;
0107 cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64);
0108 }
0109 }
0110
0111 static void __cvmx_pko_queue_alloc_o68(void)
0112 {
0113 int port;
0114
0115 for (port = 0; port < 48; port++)
0116 __cvmx_pko_iport_config(port);
0117 }
0118
0119 static void __cvmx_pko_port_map_o68(void)
0120 {
0121 int port;
0122 int interface, index;
0123 cvmx_helper_interface_mode_t mode;
0124 union cvmx_pko_mem_iport_ptrs config;
0125
0126
0127
0128
0129 config.u64 = 0;
0130 config.s.eid = 31;
0131 for (port = 0; port < 128; port++) {
0132 config.s.ipid = port;
0133 cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
0134 }
0135
0136
0137
0138
0139 for (port = 0; port < 48; port++) {
0140 interface = cvmx_helper_get_interface_num(port);
0141 index = cvmx_helper_get_interface_index_num(port);
0142 mode = cvmx_helper_interface_get_mode(interface);
0143 if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED)
0144 continue;
0145
0146 config.s.ipid = port;
0147 config.s.qos_mask = 0xff;
0148 config.s.crc = 1;
0149 config.s.min_pkt = 1;
0150 config.s.intr = __cvmx_pko_int(interface, index);
0151 config.s.eid = config.s.intr;
0152 config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ?
0153 index : port;
0154 cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
0155 }
0156 }
0157
0158 static void __cvmx_pko_chip_init(void)
0159 {
0160 int i;
0161
0162 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
0163 __cvmx_pko_port_map_o68();
0164 __cvmx_pko_queue_alloc_o68();
0165 return;
0166 }
0167
0168
0169
0170
0171 for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) {
0172 const uint64_t priority = 8;
0173
0174 cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1,
0175 &priority);
0176 }
0177 }
0178
0179
0180
0181
0182
0183
0184
0185 void cvmx_pko_initialize_global(void)
0186 {
0187 union cvmx_pko_reg_cmd_buf config;
0188
0189
0190
0191
0192
0193
0194 config.u64 = 0;
0195 config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
0196 config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1;
0197
0198 cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64);
0199
0200
0201
0202
0203 __cvmx_pko_chip_init();
0204
0205
0206
0207
0208
0209 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
0210 || OCTEON_IS_MODEL(OCTEON_CN56XX)
0211 || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
0212 int num_interfaces = cvmx_helper_get_number_of_interfaces();
0213 int last_port =
0214 cvmx_helper_get_last_ipd_port(num_interfaces - 1);
0215 int max_queues =
0216 cvmx_pko_get_base_queue(last_port) +
0217 cvmx_pko_get_num_queues(last_port);
0218 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
0219 if (max_queues <= 32)
0220 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
0221 else if (max_queues <= 64)
0222 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
0223 } else {
0224 if (max_queues <= 64)
0225 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
0226 else if (max_queues <= 128)
0227 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
0228 }
0229 }
0230 }
0231
0232
0233
0234
0235
0236 void cvmx_pko_enable(void)
0237 {
0238 union cvmx_pko_reg_flags flags;
0239
0240 flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
0241 if (flags.s.ena_pko)
0242 cvmx_dprintf
0243 ("Warning: Enabling PKO when PKO already enabled.\n");
0244
0245 flags.s.ena_dwb = 1;
0246 flags.s.ena_pko = 1;
0247
0248
0249
0250
0251 flags.s.store_be = 1;
0252 cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64);
0253 }
0254
0255
0256
0257
0258 void cvmx_pko_disable(void)
0259 {
0260 union cvmx_pko_reg_flags pko_reg_flags;
0261 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
0262 pko_reg_flags.s.ena_pko = 0;
0263 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
0264 }
0265 EXPORT_SYMBOL_GPL(cvmx_pko_disable);
0266
0267
0268
0269
0270 static void __cvmx_pko_reset(void)
0271 {
0272 union cvmx_pko_reg_flags pko_reg_flags;
0273 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
0274 pko_reg_flags.s.reset = 1;
0275 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
0276 }
0277
0278
0279
0280
0281 void cvmx_pko_shutdown(void)
0282 {
0283 union cvmx_pko_mem_queue_ptrs config;
0284 int queue;
0285
0286 cvmx_pko_disable();
0287
0288 for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) {
0289 config.u64 = 0;
0290 config.s.tail = 1;
0291 config.s.index = 0;
0292 config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID;
0293 config.s.queue = queue & 0x7f;
0294 config.s.qos_mask = 0;
0295 config.s.buf_ptr = 0;
0296 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
0297 union cvmx_pko_reg_queue_ptrs1 config1;
0298 config1.u64 = 0;
0299 config1.s.qid7 = queue >> 7;
0300 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
0301 }
0302 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
0303 cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue));
0304 }
0305 __cvmx_pko_reset();
0306 }
0307 EXPORT_SYMBOL_GPL(cvmx_pko_shutdown);
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue,
0327 uint64_t num_queues,
0328 const uint64_t priority[])
0329 {
0330 cvmx_pko_status_t result_code;
0331 uint64_t queue;
0332 union cvmx_pko_mem_queue_ptrs config;
0333 union cvmx_pko_reg_queue_ptrs1 config1;
0334 int static_priority_base = -1;
0335 int static_priority_end = -1;
0336
0337 if (OCTEON_IS_MODEL(OCTEON_CN68XX))
0338 return CVMX_PKO_SUCCESS;
0339
0340 if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS)
0341 && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) {
0342 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n",
0343 (unsigned long long)port);
0344 return CVMX_PKO_INVALID_PORT;
0345 }
0346
0347 if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) {
0348 cvmx_dprintf
0349 ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n",
0350 (unsigned long long)(base_queue + num_queues));
0351 return CVMX_PKO_INVALID_QUEUE;
0352 }
0353
0354 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
0355
0356
0357
0358
0359
0360 for (queue = 0; queue < num_queues; queue++) {
0361
0362 if (static_priority_base == -1
0363 && priority[queue] ==
0364 CVMX_PKO_QUEUE_STATIC_PRIORITY)
0365 static_priority_base = queue;
0366
0367 if (static_priority_base != -1
0368 && static_priority_end == -1
0369 && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY
0370 && queue)
0371 static_priority_end = queue - 1;
0372 else if (static_priority_base != -1
0373 && static_priority_end == -1
0374 && queue == num_queues - 1)
0375
0376 static_priority_end = queue;
0377
0378
0379
0380
0381
0382
0383 if (static_priority_end != -1
0384 && (int)queue > static_priority_end
0385 && priority[queue] ==
0386 CVMX_PKO_QUEUE_STATIC_PRIORITY) {
0387 cvmx_dprintf("ERROR: cvmx_pko_config_port: "
0388 "Static priority queues aren't "
0389 "contiguous or don't start at "
0390 "base queue. q: %d, eq: %d\n",
0391 (int)queue, static_priority_end);
0392 return CVMX_PKO_INVALID_PRIORITY;
0393 }
0394 }
0395 if (static_priority_base > 0) {
0396 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static "
0397 "priority queues don't start at base "
0398 "queue. sq: %d\n",
0399 static_priority_base);
0400 return CVMX_PKO_INVALID_PRIORITY;
0401 }
0402 #if 0
0403 cvmx_dprintf("Port %d: Static priority queue base: %d, "
0404 "end: %d\n", port,
0405 static_priority_base, static_priority_end);
0406 #endif
0407 }
0408
0409
0410
0411
0412
0413
0414 result_code = CVMX_PKO_SUCCESS;
0415
0416 #ifdef PKO_DEBUG
0417 cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues,
0418 CVMX_PKO_QUEUES_PER_PORT_INTERFACE0,
0419 CVMX_PKO_QUEUES_PER_PORT_INTERFACE1);
0420 #endif
0421
0422 for (queue = 0; queue < num_queues; queue++) {
0423 uint64_t *buf_ptr = NULL;
0424
0425 config1.u64 = 0;
0426 config1.s.idx3 = queue >> 3;
0427 config1.s.qid7 = (base_queue + queue) >> 7;
0428
0429 config.u64 = 0;
0430 config.s.tail = queue == (num_queues - 1);
0431 config.s.index = queue;
0432 config.s.port = port;
0433 config.s.queue = base_queue + queue;
0434
0435 if (!cvmx_octeon_is_pass1()) {
0436 config.s.static_p = static_priority_base >= 0;
0437 config.s.static_q = (int)queue <= static_priority_end;
0438 config.s.s_tail = (int)queue == static_priority_end;
0439 }
0440
0441
0442
0443
0444
0445 switch ((int)priority[queue]) {
0446 case 0:
0447 config.s.qos_mask = 0x00;
0448 break;
0449 case 1:
0450 config.s.qos_mask = 0x01;
0451 break;
0452 case 2:
0453 config.s.qos_mask = 0x11;
0454 break;
0455 case 3:
0456 config.s.qos_mask = 0x49;
0457 break;
0458 case 4:
0459 config.s.qos_mask = 0x55;
0460 break;
0461 case 5:
0462 config.s.qos_mask = 0x57;
0463 break;
0464 case 6:
0465 config.s.qos_mask = 0x77;
0466 break;
0467 case 7:
0468 config.s.qos_mask = 0x7f;
0469 break;
0470 case 8:
0471 config.s.qos_mask = 0xff;
0472 break;
0473 case CVMX_PKO_QUEUE_STATIC_PRIORITY:
0474 if (!cvmx_octeon_is_pass1()) {
0475 config.s.qos_mask = 0xff;
0476 break;
0477 }
0478 fallthrough;
0479 default:
0480 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid "
0481 "priority %llu\n",
0482 (unsigned long long)priority[queue]);
0483 config.s.qos_mask = 0xff;
0484 result_code = CVMX_PKO_INVALID_PRIORITY;
0485 break;
0486 }
0487
0488 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
0489 cvmx_cmd_queue_result_t cmd_res =
0490 cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO
0491 (base_queue + queue),
0492 CVMX_PKO_MAX_QUEUE_DEPTH,
0493 CVMX_FPA_OUTPUT_BUFFER_POOL,
0494 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
0495 -
0496 CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST
0497 * 8);
0498 if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) {
0499 switch (cmd_res) {
0500 case CVMX_CMD_QUEUE_NO_MEMORY:
0501 cvmx_dprintf("ERROR: "
0502 "cvmx_pko_config_port: "
0503 "Unable to allocate "
0504 "output buffer.\n");
0505 return CVMX_PKO_NO_MEMORY;
0506 case CVMX_CMD_QUEUE_ALREADY_SETUP:
0507 cvmx_dprintf
0508 ("ERROR: cvmx_pko_config_port: Port already setup.\n");
0509 return CVMX_PKO_PORT_ALREADY_SETUP;
0510 case CVMX_CMD_QUEUE_INVALID_PARAM:
0511 default:
0512 cvmx_dprintf
0513 ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n");
0514 return CVMX_PKO_CMD_QUEUE_INIT_ERROR;
0515 }
0516 }
0517
0518 buf_ptr =
0519 (uint64_t *)
0520 cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO
0521 (base_queue + queue));
0522 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr);
0523 } else
0524 config.s.buf_ptr = 0;
0525
0526 CVMX_SYNCWS;
0527
0528 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX))
0529 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
0530 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
0531 }
0532
0533 return result_code;
0534 }
0535
0536 #ifdef PKO_DEBUG
0537
0538
0539
0540 void cvmx_pko_show_queue_map()
0541 {
0542 int core, port;
0543 int pko_output_ports = 36;
0544
0545 cvmx_dprintf("port");
0546 for (port = 0; port < pko_output_ports; port++)
0547 cvmx_dprintf("%3d ", port);
0548 cvmx_dprintf("\n");
0549
0550 for (core = 0; core < CVMX_MAX_CORES; core++) {
0551 cvmx_dprintf("\n%2d: ", core);
0552 for (port = 0; port < pko_output_ports; port++) {
0553 cvmx_dprintf("%3d ",
0554 cvmx_pko_get_base_queue_per_core(port,
0555 core));
0556 }
0557 }
0558 cvmx_dprintf("\n");
0559 }
0560 #endif
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573 int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst)
0574 {
0575 union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
0576 union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
0577
0578 pko_mem_port_rate0.u64 = 0;
0579 pko_mem_port_rate0.s.pid = port;
0580 pko_mem_port_rate0.s.rate_pkt =
0581 cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16;
0582
0583 pko_mem_port_rate0.s.rate_word = 0;
0584
0585 pko_mem_port_rate1.u64 = 0;
0586 pko_mem_port_rate1.s.pid = port;
0587 pko_mem_port_rate1.s.rate_lim =
0588 ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8;
0589
0590 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
0591 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
0592 return 0;
0593 }
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606 int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst)
0607 {
0608 union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
0609 union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
0610 uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz;
0611 uint64_t tokens_per_bit = clock_rate * 16 / bits_s;
0612
0613 pko_mem_port_rate0.u64 = 0;
0614 pko_mem_port_rate0.s.pid = port;
0615
0616
0617
0618
0619
0620
0621 pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
0622
0623 pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit;
0624
0625 pko_mem_port_rate1.u64 = 0;
0626 pko_mem_port_rate1.s.pid = port;
0627 pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256;
0628
0629 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
0630 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
0631 return 0;
0632 }