Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cvmx-helper-util.c
Go to the documentation of this file.
1 /***********************license start***************
2  * Author: Cavium Networks
3  *
4  * Contact: [email protected]
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2008 Cavium Networks
8  *
9  * This file is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License, Version 2, as
11  * published by the Free Software Foundation.
12  *
13  * This file is distributed in the hope that it will be useful, but
14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16  * NONINFRINGEMENT. See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this file; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  * or visit http://www.gnu.org/licenses/.
23  *
24  * This file may also be available under a different license from Cavium.
25  * Contact Cavium Networks for more information
26  ***********************license end**************************************/
27 
28 /*
29  * Small helper utilities.
30  */
31 #include <linux/kernel.h>
32 
33 #include <asm/octeon/octeon.h>
34 
35 #include <asm/octeon/cvmx-config.h>
36 
37 #include <asm/octeon/cvmx-fpa.h>
38 #include <asm/octeon/cvmx-pip.h>
39 #include <asm/octeon/cvmx-pko.h>
40 #include <asm/octeon/cvmx-ipd.h>
41 #include <asm/octeon/cvmx-spi.h>
42 
43 #include <asm/octeon/cvmx-helper.h>
45 
47 
56  mode)
57 {
58  switch (mode) {
60  return "DISABLED";
62  return "RGMII";
64  return "GMII";
66  return "SPI";
68  return "PCIE";
70  return "XAUI";
72  return "SGMII";
74  return "PICMG";
76  return "NPI";
78  return "LOOP";
79  }
80  return "UNKNOWN";
81 }
82 
89 int cvmx_helper_dump_packet(cvmx_wqe_t *work)
90 {
92  uint64_t remaining_bytes;
93  union cvmx_buf_ptr buffer_ptr;
94  uint64_t start_of_buffer;
97 
98  cvmx_dprintf("Packet Length: %u\n", work->len);
99  cvmx_dprintf(" Input Port: %u\n", work->ipprt);
100  cvmx_dprintf(" QoS: %u\n", work->qos);
101  cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs);
102 
103  if (work->word2.s.bufs == 0) {
104  union cvmx_ipd_wqe_fpa_queue wqe_pool;
105  wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE);
106  buffer_ptr.u64 = 0;
107  buffer_ptr.s.pool = wqe_pool.s.wqe_pool;
108  buffer_ptr.s.size = 128;
109  buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data);
110  if (likely(!work->word2.s.not_IP)) {
111  union cvmx_pip_ip_offset pip_ip_offset;
112  pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET);
113  buffer_ptr.s.addr +=
114  (pip_ip_offset.s.offset << 3) -
115  work->word2.s.ip_offset;
116  buffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2;
117  } else {
118  /*
119  * WARNING: This code assumes that the packet
120  * is not RAW. If it was, we would use
121  * PIP_GBL_CFG[RAW_SHF] instead of
122  * PIP_GBL_CFG[NIP_SHF].
123  */
124  union cvmx_pip_gbl_cfg pip_gbl_cfg;
125  pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG);
126  buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf;
127  }
128  } else
129  buffer_ptr = work->packet_ptr;
130  remaining_bytes = work->len;
131 
132  while (remaining_bytes) {
133  start_of_buffer =
134  ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7;
135  cvmx_dprintf(" Buffer Start:%llx\n",
136  (unsigned long long)start_of_buffer);
137  cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i);
138  cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back);
139  cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool);
140  cvmx_dprintf(" Buffer Data: %llx\n",
141  (unsigned long long)buffer_ptr.s.addr);
142  cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size);
143 
144  cvmx_dprintf("\t\t");
145  data_address = (uint8_t *) cvmx_phys_to_ptr(buffer_ptr.s.addr);
146  end_of_data = data_address + buffer_ptr.s.size;
147  count = 0;
148  while (data_address < end_of_data) {
149  if (remaining_bytes == 0)
150  break;
151  else
152  remaining_bytes--;
153  cvmx_dprintf("%02x", (unsigned int)*data_address);
154  data_address++;
155  if (remaining_bytes && (count == 7)) {
156  cvmx_dprintf("\n\t\t");
157  count = 0;
158  } else
159  count++;
160  }
161  cvmx_dprintf("\n");
162 
163  if (remaining_bytes)
164  buffer_ptr = *(union cvmx_buf_ptr *)
165  cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
166  }
167  return 0;
168 }
169 
182 int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh)
183 {
184  union cvmx_ipd_qosx_red_marks red_marks;
185  union cvmx_ipd_red_quex_param red_param;
186 
187  /* Set RED to begin dropping packets when there are pass_thresh buffers
188  left. It will linearly drop more packets until reaching drop_thresh
189  buffers */
190  red_marks.u64 = 0;
191  red_marks.s.drop = drop_thresh;
192  red_marks.s.pass = pass_thresh;
193  cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64);
194 
195  /* Use the actual queue 0 counter, not the average */
196  red_param.u64 = 0;
197  red_param.s.prb_con =
198  (255ul << 24) / (red_marks.s.pass - red_marks.s.drop);
199  red_param.s.avg_con = 1;
200  red_param.s.new_con = 255;
201  red_param.s.use_pcnt = 1;
202  cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64);
203  return 0;
204 }
205 
217 int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
218 {
219  union cvmx_ipd_portx_bp_page_cnt page_cnt;
220  union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end;
221  union cvmx_ipd_red_port_enable red_port_enable;
222  int queue;
223  int interface;
224  int port;
225 
226  /* Disable backpressure based on queued buffers. It needs SW support */
227  page_cnt.u64 = 0;
228  page_cnt.s.bp_enb = 0;
229  page_cnt.s.page_cnt = 100;
230  for (interface = 0; interface < 2; interface++) {
231  for (port = cvmx_helper_get_first_ipd_port(interface);
232  port < cvmx_helper_get_last_ipd_port(interface); port++)
233  cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port),
234  page_cnt.u64);
235  }
236 
237  for (queue = 0; queue < 8; queue++)
238  cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh);
239 
240  /* Shutoff the dropping based on the per port page count. SW isn't
241  decrementing it right now */
242  ipd_bp_prt_red_end.u64 = 0;
243  ipd_bp_prt_red_end.s.prt_enb = 0;
244  cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64);
245 
246  red_port_enable.u64 = 0;
247  red_port_enable.s.prt_enb = 0xfffffffffull;
248  red_port_enable.s.avg_dly = 10000;
249  red_port_enable.s.prb_dly = 10000;
250  cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64);
251 
252  return 0;
253 }
254 
265 int __cvmx_helper_setup_gmx(int interface, int num_ports)
266 {
267  union cvmx_gmxx_tx_prts gmx_tx_prts;
268  union cvmx_gmxx_rx_prts gmx_rx_prts;
269  union cvmx_pko_reg_gmx_port_mode pko_mode;
270  union cvmx_gmxx_txx_thresh gmx_tx_thresh;
271  int index;
272 
273  /* Tell GMX the number of TX ports on this interface */
274  gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface));
275  gmx_tx_prts.s.prts = num_ports;
276  cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64);
277 
278  /* Tell GMX the number of RX ports on this interface. This only
279  ** applies to *GMII and XAUI ports */
280  if (cvmx_helper_interface_get_mode(interface) ==
282  || cvmx_helper_interface_get_mode(interface) ==
284  || cvmx_helper_interface_get_mode(interface) ==
286  || cvmx_helper_interface_get_mode(interface) ==
288  if (num_ports > 4) {
289  cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal "
290  "num_ports\n");
291  return -1;
292  }
293 
294  gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface));
295  gmx_rx_prts.s.prts = num_ports;
296  cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64);
297  }
298 
299  /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */
302  /* Tell PKO the number of ports on this interface */
303  pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE);
304  if (interface == 0) {
305  if (num_ports == 1)
306  pko_mode.s.mode0 = 4;
307  else if (num_ports == 2)
308  pko_mode.s.mode0 = 3;
309  else if (num_ports <= 4)
310  pko_mode.s.mode0 = 2;
311  else if (num_ports <= 8)
312  pko_mode.s.mode0 = 1;
313  else
314  pko_mode.s.mode0 = 0;
315  } else {
316  if (num_ports == 1)
317  pko_mode.s.mode1 = 4;
318  else if (num_ports == 2)
319  pko_mode.s.mode1 = 3;
320  else if (num_ports <= 4)
321  pko_mode.s.mode1 = 2;
322  else if (num_ports <= 8)
323  pko_mode.s.mode1 = 1;
324  else
325  pko_mode.s.mode1 = 0;
326  }
327  cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
328  }
329 
330  /*
331  * Set GMX to buffer as much data as possible before starting
332  * transmit. This reduces the chances that we have a TX under
333  * run due to memory contention. Any packet that fits entirely
334  * in the GMX FIFO can never have an under run regardless of
335  * memory load.
336  */
337  gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface));
340  /* These chips have a fixed max threshold of 0x40 */
341  gmx_tx_thresh.s.cnt = 0x40;
342  } else {
343  /* Choose the max value for the number of ports */
344  if (num_ports <= 1)
345  gmx_tx_thresh.s.cnt = 0x100 / 1;
346  else if (num_ports == 2)
347  gmx_tx_thresh.s.cnt = 0x100 / 2;
348  else
349  gmx_tx_thresh.s.cnt = 0x100 / 4;
350  }
351  /*
352  * SPI and XAUI can have lots of ports but the GMX hardware
353  * only ever has a max of 4.
354  */
355  if (num_ports > 4)
356  num_ports = 4;
357  for (index = 0; index < num_ports; index++)
358  cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface),
359  gmx_tx_thresh.u64);
360 
361  return 0;
362 }
363 
374 {
375  switch (interface) {
376  case 0:
377  return port;
378  case 1:
379  return port + 16;
380  case 2:
381  return port + 32;
382  case 3:
383  return port + 36;
384  }
385  return -1;
386 }
387 
396 {
397  if (ipd_port < 16)
398  return 0;
399  else if (ipd_port < 32)
400  return 1;
401  else if (ipd_port < 36)
402  return 2;
403  else if (ipd_port < 40)
404  return 3;
405  else
406  cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD "
407  "port number\n");
408 
409  return -1;
410 }
411 
421 {
422  if (ipd_port < 32)
423  return ipd_port & 15;
424  else if (ipd_port < 36)
425  return ipd_port & 3;
426  else if (ipd_port < 40)
427  return ipd_port & 3;
428  else
429  cvmx_dprintf("cvmx_helper_get_interface_index_num: "
430  "Illegal IPD port number\n");
431 
432  return -1;
433 }