]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/mips/cavium/dev/rgmii/octeon_pko.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / mips / cavium / dev / rgmii / octeon_pko.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (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 Networks 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  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39 /*------------------------------------------------------------------
40  * octeon_pko.c      Packet Output Unit
41  *
42  *------------------------------------------------------------------
43  */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52
53 #include <mips/cavium/octeon_pcmap_regs.h>
54 #include "octeon_fau.h"
55 #include "octeon_fpa.h"
56 #include "octeon_pko.h"
57
58
59 /*
60  *
61  */
62 static void octeon_pko_clear_port_counts (u_int port)
63 {
64     u_int port_num;
65     octeon_pko_read_idx_t octeon_pko_idx;
66
67     octeon_pko_idx.word64 = 0;
68     octeon_pko_idx.bits.idx = port;
69     octeon_pko_idx.bits.inc = 0;
70     oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
71
72     port_num = port;
73     oct_write64(OCTEON_PKO_MEM_COUNT0, port_num);
74     port_num = port;
75     oct_write64(OCTEON_PKO_MEM_COUNT1, port_num);
76 }
77
78 /*
79  * octeon_pko_init
80  *
81  */
82 void octeon_pko_init (void)
83 {
84     u_int queue, port;
85     octeon_pko_read_idx_t octeon_pko_idx;
86     octeon_pko_queue_cfg_t octeon_pko_queue_cfg;
87
88     for (port = 0; port < OCTEON_PKO_PORTS_MAX; port++) {
89         octeon_pko_clear_port_counts(port);
90     }
91
92     octeon_pko_idx.word64 = 0;
93     octeon_pko_idx.bits.idx = 0;
94     octeon_pko_idx.bits.inc = 1;
95     oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
96     for (queue = 0; queue < OCTEON_PKO_QUEUES_MAX; queue++) {
97
98         octeon_pko_queue_cfg.word64 = 0;
99         octeon_pko_queue_cfg.bits.queue = queue;
100         octeon_pko_queue_cfg.bits.port =  OCTEON_PKO_PORT_ILLEGAL;
101         octeon_pko_queue_cfg.bits.buf_ptr = 0;
102         oct_write64(OCTEON_PKO_MEM_QUEUE_PTRS, octeon_pko_queue_cfg.word64);
103     }
104 }
105
106
107 /*
108  * octeon_pko_enable
109  *
110  * enable pko
111  */
112 void octeon_pko_enable (void)
113 {
114
115     /*
116      * PKO enable
117      */
118     oct_write64(OCTEON_PKO_REG_FLAGS, 3);    /*  octeon_pko_enable() */
119 }
120
121
122 /*
123  * octeon_pko_disable
124  *
125  * disable pko
126  */
127 void octeon_pko_disable (void)
128 {
129
130     /*
131      * PKO disable
132      */
133     oct_write64(OCTEON_PKO_REG_FLAGS, 0);    /*  pko_disable() */
134 }
135
136 /*
137  * octeon_pko_config_cmdbuf_global_defaults
138  *
139  */
140 void octeon_pko_config_cmdbuf_global_defaults (u_int cmdbuf_pool,
141                                                u_int cmdbuf_pool_elem_size )
142 {
143     octeon_pko_pool_cfg_t octeon_pko_pool_config;
144
145     octeon_pko_pool_config.word64 = 0;
146     octeon_pko_pool_config.bits.pool = cmdbuf_pool;
147     octeon_pko_pool_config.bits.size = cmdbuf_pool_elem_size;
148     oct_write64(OCTEON_PKO_CMD_BUF, octeon_pko_pool_config.word64);
149 }
150
151 /*
152  * octeon_pko_config_rgmx_ports
153  *
154  * Configure rgmx pko.  Always enables 4 + 4 ports
155  */
156 void octeon_pko_config_rgmx_ports (void)
157 {
158     octeon_pko_reg_gmx_port_mode_t octeon_pko_gmx_mode;
159
160     octeon_pko_gmx_mode.word64 = 0;
161     octeon_pko_gmx_mode.bits.mode0 = 2; /* 16 >> 2 == 4 ports */
162     octeon_pko_gmx_mode.bits.mode1 = 2; /* 16 >> 2 == 4 ports */
163     oct_write64(OCTEON_PKO_GMX_PORT_MODE, octeon_pko_gmx_mode.word64);
164 }
165
166
167 /*
168  * octeon_pko_config
169  *
170  * Configure PKO
171  *
172  */
173 void octeon_pko_config (void)
174 {
175 }
176
177 /*
178  * octeon_pko_get_port_status
179  *
180  * Get the status counters for a PKO port.
181  *
182  * port_num Port number to get statistics for.
183  * clear    Set to 1 to clear the counters after they are read
184  * status   Where to put the results.
185  */
186 void octeon_pko_get_port_status (u_int port, u_int clear,
187                                  octeon_pko_port_status_t *status)
188 {
189     octeon_word_t packet_num;
190     octeon_pko_read_idx_t octeon_pko_idx;
191
192     packet_num.word64 = 0;
193
194     octeon_pko_idx.word64 = 0;
195     octeon_pko_idx.bits.idx = port;
196     octeon_pko_idx.bits.inc = 0;
197     oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
198
199     packet_num.word64 = oct_read64(OCTEON_PKO_MEM_COUNT0);
200     status->packets = packet_num.bits.word32lo;
201
202     status->octets = oct_read64(OCTEON_PKO_MEM_COUNT1);
203     status->doorbell = oct_read64(OCTEON_PKO_MEM_DEBUG9);
204     status->doorbell = (status->doorbell >> 8) & 0xfffff;
205     if (clear) {
206         octeon_pko_clear_port_counts(port);
207     }
208 }
209
210 static void octeon_pko_doorbell_data_dump(uint64_t port);
211
212 static void octeon_pko_doorbell_data_dump (uint64_t port)
213 {
214     octeon_pko_port_status_t status;
215
216     octeon_pko_get_port_status(port, 0, &status);
217     printf("\n Port #%lld  Pkts %ld   Bytes %lld  DoorBell %lld",
218         (unsigned long long)port, status.packets,
219         (unsigned long long)status.octets,
220         (unsigned long long)status.doorbell);
221 }
222
223 /*
224  * octeon_pko_show
225  *
226  * Show the OCTEON_PKO status & configs
227  */
228 void octeon_pko_show (u_int start_port, u_int end_port)
229 {
230     u_int queue, queue_max, gmx_int0_ports, gmx_int1_ports;
231     u_int port;
232     uint64_t val64;
233     octeon_pko_port_status_t status;
234     octeon_pko_pool_cfg_t octeon_pko_pool_config;
235     octeon_pko_read_idx_t octeon_pko_idx;
236     octeon_pko_queue_mode_t octeon_pko_queue_mode;
237     octeon_pko_reg_gmx_port_mode_t octeon_pko_gmx_mode;
238     octeon_pko_crc_ports_enable_t octeon_pko_crc_ports;
239     octeon_pko_queue_cfg_t octeon_pko_queue_cfg;
240
241     printf("\n\nPKO Status:");
242     val64 = oct_read64(OCTEON_PKO_REG_FLAGS);
243     if ((val64 & 0x3) != 0x3) {
244         printf("  Disabled");
245         return;
246     } else {
247         printf("  Enabled");
248     }
249     octeon_pko_queue_mode.word64 = oct_read64(OCTEON_PKO_QUEUE_MODE);
250     queue_max = (128 >> octeon_pko_queue_mode.bits.mode);
251     octeon_pko_gmx_mode.word64 = oct_read64(OCTEON_PKO_GMX_PORT_MODE);
252     gmx_int0_ports = (16 >> octeon_pko_gmx_mode.bits.mode0);
253     gmx_int1_ports = (16 >> octeon_pko_gmx_mode.bits.mode1);
254     octeon_pko_crc_ports.word64 = oct_read64(OCTEON_PKO_REG_CRC_ENABLE);
255     printf("\n Total Queues: 0..%d  Ports GMX0 %d   GMX1 %d  CRC 0x%X",
256            queue_max - 1, gmx_int0_ports, gmx_int1_ports,
257            octeon_pko_crc_ports.bits.crc_ports_mask);
258
259     octeon_pko_pool_config.word64 = oct_read64(OCTEON_PKO_CMD_BUF);
260     printf("\n  CmdBuf Pool: %d    CmdBuf  Size in Words: %d  Bytes: %d",
261            octeon_pko_pool_config.bits.pool, octeon_pko_pool_config.bits.size,
262            octeon_pko_pool_config.bits.size * 8);
263
264     octeon_pko_idx.word64 = 0;
265     octeon_pko_idx.bits.idx = 0;
266     octeon_pko_idx.bits.inc = 1;
267     oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
268     for (queue = 0; queue < queue_max; queue++) {
269
270         octeon_pko_queue_cfg.word64 = oct_read64(OCTEON_PKO_MEM_QUEUE_PTRS);
271         if (!octeon_pko_queue_cfg.bits.buf_ptr) continue;
272         printf("\n  Port # %d   Queue %3d   [%d]  BufPtr: 0x%llX Mask: %X%s",
273                octeon_pko_queue_cfg.bits.port, octeon_pko_queue_cfg.bits.queue,
274                octeon_pko_queue_cfg.bits.index,
275                (unsigned long long)octeon_pko_queue_cfg.bits.buf_ptr,
276                octeon_pko_queue_cfg.bits.qos_mask,
277                (octeon_pko_queue_cfg.bits.tail)? "  Last":"");
278     }
279     printf("\n");
280
281     for (port = start_port; port < (end_port + 1); port++) {
282
283         octeon_pko_get_port_status(port, 0, &status);
284         octeon_pko_doorbell_data_dump(port);
285
286     }
287 }
288
289
290
291
292 /*
293  * octeon_pko_config_port
294  *
295  * Configure a output port and the associated queues for use.
296  *
297  */
298 octeon_pko_status_t octeon_pko_config_port (u_int port,
299                                             u_int base_queue,
300                                             u_int num_queues,
301                                             const u_int priority[],
302                                             u_int pko_output_cmdbuf_fpa_pool,
303                                             octeon_pko_sw_queue_info_t sw_queues[])
304 {
305     octeon_pko_status_t result_code;
306     u_int               queue;
307     octeon_pko_queue_cfg_t      qconfig;
308
309     if ((port >= OCTEON_PKO_PORTS_MAX) && (port != OCTEON_PKO_PORT_ILLEGAL)) {
310         printf("\n%% Error: octeon_pko_config_port: Invalid port %u", port);
311         return (OCTEON_PKO_INVALID_PORT);
312     }
313
314     if ((base_queue + num_queues) > OCTEON_PKO_QUEUES_MAX) {
315         printf("\n%% Error: octeon_pko_config_port: Invalid queue range");
316         return (OCTEON_PKO_INVALID_QUEUE);
317     }
318
319     result_code = OCTEON_PKO_SUCCESS;
320
321     for (queue = 0; queue < num_queues; queue++) {
322         uint64_t  buf_ptr = 0;
323
324         qconfig.word64          = 0;
325         qconfig.bits.tail       = (queue == (num_queues - 1)) ? 1 : 0;
326         qconfig.bits.index      = queue;
327         qconfig.bits.port       = port;
328         qconfig.bits.queue      = base_queue + queue;
329
330         /* Convert the priority into an enable bit field. */
331         /* Try to space the bits out evenly so the pkts don't get grouped up */
332         switch ((int)priority[queue]) {
333             case 0: qconfig.bits.qos_mask = 0x00; break;
334             case 1: qconfig.bits.qos_mask = 0x01; break;
335             case 2: qconfig.bits.qos_mask = 0x11; break;
336             case 3: qconfig.bits.qos_mask = 0x49; break;
337             case 4: qconfig.bits.qos_mask = 0x55; break;
338             case 5: qconfig.bits.qos_mask = 0x57; break;
339             case 6: qconfig.bits.qos_mask = 0x77; break;
340             case 7: qconfig.bits.qos_mask = 0x7f; break;
341             case 8: qconfig.bits.qos_mask = 0xff; break;
342             default:
343                 printf("\n%% Error: octeon_pko_config_port Invalid priority %llu",
344                        (unsigned long long)priority[queue]);
345                 qconfig.bits.qos_mask = 0xff;
346                 result_code = OCTEON_PKO_INVALID_PRIORITY;
347                 break;
348         }
349         if (port != OCTEON_PKO_PORT_ILLEGAL) {
350
351             buf_ptr = octeon_fpa_alloc_phys(pko_output_cmdbuf_fpa_pool);
352             if (!buf_ptr) {
353                 printf("\n%% Error: octeon_pko_config_port: Unable to allocate");
354                 return (OCTEON_PKO_NO_MEMORY);
355             }
356
357             sw_queues[queue].xmit_command_state = (buf_ptr << OCTEON_PKO_INDEX_BITS);
358             octeon_spinlock_init(&(sw_queues[queue].lock));
359
360 //#define DEBUG_TX
361
362 #ifdef DEBUG_TX
363             printf(" PKO: port %u pool: %u  base+queue %u %u %u  buf_ptr: 0x%llX\n",
364                    port,
365                    pko_output_cmdbuf_fpa_pool,
366                    base_queue, queue, base_queue+queue,
367                    buf_ptr);
368
369 #endif
370             qconfig.bits.buf_ptr = buf_ptr;
371             oct_write64(OCTEON_PKO_MEM_QUEUE_PTRS, qconfig.word64);
372
373         }
374     }
375
376     return (result_code);
377 }
378