Back to home page

OSCL-LXR

 
 

    


0001 /***********************license start***************
0002  * Author: Cavium Networks
0003  *
0004  * Contact: support@caviumnetworks.com
0005  * This file is part of the OCTEON SDK
0006  *
0007  * Copyright (c) 2003-2008 Cavium Networks
0008  *
0009  * This file is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License, Version 2, as
0011  * published by the Free Software Foundation.
0012  *
0013  * This file is distributed in the hope that it will be useful, but
0014  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
0015  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
0016  * NONINFRINGEMENT.  See the GNU General Public License for more
0017  * details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this file; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0022  * or visit http://www.gnu.org/licenses/.
0023  *
0024  * This file may also be available under a different license from Cavium.
0025  * Contact Cavium Networks for more information
0026  ***********************license end**************************************/
0027 
0028 /*
0029  * Support library for the hardware Packet Output unit.
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  * Internal state of packet output
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      * Initialize every iport with the invalid eid.
0128      */
0129     config.u64 = 0;
0130     config.s.eid = 31; /* Invalid */
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      * Set up PKO_MEM_IPORT_PTRS
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      * Initialize queues
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  * Call before any other calls to initialize the packet
0181  * output system.  This does chip global config, and should only be
0182  * done by one core.
0183  */
0184 
0185 void cvmx_pko_initialize_global(void)
0186 {
0187     union cvmx_pko_reg_cmd_buf config;
0188 
0189     /*
0190      * Set the size of the PKO command buffers to an odd number of
0191      * 64bit words. This allows the normal two word send to stay
0192      * aligned and never span a command word buffer.
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      * Chip-specific setup.
0202      */
0203     __cvmx_pko_chip_init();
0204 
0205     /*
0206      * If we aren't using all of the queues optimize PKO's
0207      * internal memory.
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  * Enables the packet output hardware. It must already be
0234  * configured.
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      * always enable big endian for 3-word command. Does nothing
0249      * for 2-word.
0250      */
0251     flags.s.store_be = 1;
0252     cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64);
0253 }
0254 
0255 /*
0256  * Disables the packet output. Does not affect any configuration.
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  * Reset the packet output.
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  * Shutdown and free resources required by packet output.
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  * Configure a output port and the associated queues for use.
0311  *
0312  * @port:   Port to configure.
0313  * @base_queue: First queue number to associate with this port.
0314  * @num_queues: Number of queues to associate with this port
0315  * @priority:   Array of priority levels for each queue. Values are
0316  *           allowed to be 0-8. A value of 8 get 8 times the traffic
0317  *           of a value of 1.  A value of 0 indicates that no rounds
0318  *           will be participated in. These priorities can be changed
0319  *           on the fly while the pko is enabled. A priority of 9
0320  *           indicates that static priority should be used.  If static
0321  *           priority is used all queues with static priority must be
0322  *           contiguous starting at the base_queue, and lower numbered
0323  *           queues have higher priority than higher numbered queues.
0324  *           There must be num_queues elements in the array.
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          * Validate the static queue priority setup and set
0357          * static_priority_base and static_priority_end
0358          * accordingly.
0359          */
0360         for (queue = 0; queue < num_queues; queue++) {
0361             /* Find first queue of static priority */
0362             if (static_priority_base == -1
0363                 && priority[queue] ==
0364                 CVMX_PKO_QUEUE_STATIC_PRIORITY)
0365                 static_priority_base = queue;
0366             /* Find last queue of static priority */
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                 /* all queues are static priority */
0376                 static_priority_end = queue;
0377             /*
0378              * Check to make sure all static priority
0379              * queues are contiguous.  Also catches some
0380              * cases of static priorities not starting at
0381              * queue 0.
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      * At this point, static_priority_base and static_priority_end
0410      * are either both -1, or are valid start/end queue
0411      * numbers.
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          * Convert the priority into an enable bit field. Try
0442          * to space the bits out evenly so the packet don't
0443          * get grouped up
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;    /* to the error case, when Pass 1 */
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  * Show map of ports -> queues for different cores.
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  * Rate limit a PKO port to a max packets/sec. This function is only
0564  * supported on CN51XX and higher, excluding CN58XX.
0565  *
0566  * @port:      Port to rate limit
0567  * @packets_s: Maximum packet/sec
0568  * @burst:     Maximum number of packets to burst in a row before rate
0569  *          limiting cuts in.
0570  *
0571  * Returns Zero on success, negative on failure
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     /* No cost per word since we are limited by packets/sec, not bits/sec */
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  * Rate limit a PKO port to a max bits/sec. This function is only
0597  * supported on CN51XX and higher, excluding CN58XX.
0598  *
0599  * @port:   Port to rate limit
0600  * @bits_s: PKO rate limit in bits/sec
0601  * @burst:  Maximum number of bits to burst before rate
0602  *       limiting cuts in.
0603  *
0604  * Returns Zero on success, negative on failure
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      * Each packet has a 12 bytes of interframe gap, an 8 byte
0617      * preamble, and a 4 byte CRC. These are not included in the
0618      * per word count. Multiply by 8 to covert to bits and divide
0619      * by 256 for limit granularity.
0620      */
0621     pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
0622     /* Each 8 byte word has 64bits */
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 }