1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett#define CVMX_USE_1_TO_1_TLB_MAPPINGS 0
47215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
48215990Sjmallett#include <linux/kernel.h>
49215990Sjmallett#include <asm/octeon/cvmx.h>
50215990Sjmallett#include <asm/octeon/cvmx-spinlock.h>
51215990Sjmallett#include <asm/octeon/octeon-pci-console.h>
52210284Sjmallett
53215990Sjmallett#define MIN(a,b) min((a),(b))
54215990Sjmallett
55215990Sjmallett#else
56210284Sjmallett#include "cvmx-platform.h"
57210284Sjmallett
58210284Sjmallett#include "cvmx.h"
59210284Sjmallett#include "cvmx-spinlock.h"
60232812Sjmallett#ifndef MIN
61232812Sjmallett# define	MIN(a,b) (((a)<(b))?(a):(b))
62232812Sjmallett#endif
63210284Sjmallett
64210284Sjmallett#include "cvmx-bootmem.h"
65215990Sjmallett#include "octeon-pci-console.h"
66210284Sjmallett#endif
67232812Sjmallett#ifdef __U_BOOT__
68232812Sjmallett#include <watchdog.h>
69232812Sjmallett#endif
70210284Sjmallett
71210284Sjmallett#if defined(__linux__) && !defined(__KERNEL__) && !defined(OCTEON_TARGET)
72210284Sjmallett#include "octeon-pci.h"
73210284Sjmallett#endif
74210284Sjmallett
75210284Sjmallett
76210284Sjmallett/* The following code is only used in standalone CVMX applications. It does
77210284Sjmallett    not apply for kernel or Linux programming */
78242952Sjmallett#if defined(OCTEON_TARGET) && !defined(__linux__) && !defined(CVMX_BUILD_FOR_LINUX_KERNEL)
79210284Sjmallett
80210284Sjmallettstatic int cvmx_pci_console_num = 0;
81210284Sjmallettstatic int per_core_pci_consoles = 0;
82210284Sjmallettstatic uint64_t pci_console_desc_addr = 0;
83210284Sjmallett/* This function for simple executive internal use only - do not use in any application */
84210284Sjmallettint  __cvmx_pci_console_write (int fd, char *buf, int nbytes)
85210284Sjmallett{
86210284Sjmallett    int console_num;
87210284Sjmallett    if (fd >= 0x10000000)
88210284Sjmallett    {
89210284Sjmallett        console_num = fd & 0xFFFF;
90210284Sjmallett    }
91210284Sjmallett    else if (per_core_pci_consoles)
92210284Sjmallett    {
93210284Sjmallett        console_num = cvmx_get_core_num();
94210284Sjmallett    }
95210284Sjmallett    else
96210284Sjmallett        console_num = cvmx_pci_console_num;
97210284Sjmallett
98210284Sjmallett    if (!pci_console_desc_addr)
99210284Sjmallett    {
100215990Sjmallett        const cvmx_bootmem_named_block_desc_t *block_desc = cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME);
101210284Sjmallett        pci_console_desc_addr = block_desc->base_addr;
102210284Sjmallett    }
103210284Sjmallett
104210284Sjmallett
105210284Sjmallett    return octeon_pci_console_write(pci_console_desc_addr, console_num, buf, nbytes, 0);
106210284Sjmallett
107210284Sjmallett}
108210284Sjmallett
109210284Sjmallett#endif
110210284Sjmallett
111210284Sjmallett
112232812Sjmallett#if !defined(CONFIG_OCTEON_U_BOOT) || (defined(CONFIG_OCTEON_U_BOOT) && (defined(CFG_PCI_CONSOLE) || defined(CONFIG_SYS_PCI_CONSOLE)))
113242952Sjmallettstatic int octeon_pci_console_buffer_free_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx)
114210284Sjmallett{
115210284Sjmallett    if (rd_idx >= buffer_size || wr_idx >= buffer_size)
116210284Sjmallett        return -1;
117210284Sjmallett
118210284Sjmallett    return (((buffer_size -1) - (wr_idx - rd_idx))%buffer_size);
119210284Sjmallett}
120242952Sjmallettstatic int octeon_pci_console_buffer_avail_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx)
121210284Sjmallett{
122210284Sjmallett    if (rd_idx >= buffer_size || wr_idx >= buffer_size)
123210284Sjmallett        return -1;
124210284Sjmallett
125210284Sjmallett    return (buffer_size - 1 - octeon_pci_console_buffer_free_bytes(buffer_size, wr_idx, rd_idx));
126210284Sjmallett}
127210284Sjmallett#endif
128210284Sjmallett
129210284Sjmallett
130210284Sjmallett
131210284Sjmallett/* The following code is only used under Linux userspace when you are using
132210284Sjmallett    CVMX */
133210284Sjmallett#if defined(__linux__) && !defined(__KERNEL__) && !defined(OCTEON_TARGET)
134210284Sjmallettint octeon_pci_console_host_write(uint64_t console_desc_addr, unsigned int console_num, const char * buffer, int write_reqest_size, uint32_t flags)
135210284Sjmallett{
136210284Sjmallett    if (!console_desc_addr)
137210284Sjmallett        return -1;
138210284Sjmallett
139210284Sjmallett    /* Get global pci console information and look up specific console structure. */
140210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
141210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
142210284Sjmallett    if (console_num >= num_consoles)
143210284Sjmallett    {
144210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
145210284Sjmallett        return(-1);
146210284Sjmallett    }
147210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
148210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
149210284Sjmallett
150210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
151210284Sjmallett    /* Check to see if any data is available */
152210284Sjmallett    uint32_t rd_idx, wr_idx;
153210284Sjmallett    uint64_t base_addr;
154210284Sjmallett
155210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, input_base_addr));
156210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_read_index));
157210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index));
158210284Sjmallett
159210284Sjmallett//    printf("Input base: 0x%llx, rd: %d(0x%x), wr: %d(0x%x)\n", (long long)base_addr, rd_idx, rd_idx, wr_idx, wr_idx);
160210284Sjmallett    int bytes_to_write = octeon_pci_console_buffer_free_bytes(console_buffer_size, wr_idx, rd_idx);
161210284Sjmallett    if (bytes_to_write <= 0)
162210284Sjmallett        return bytes_to_write;
163210284Sjmallett    bytes_to_write = MIN(bytes_to_write, write_reqest_size);
164210284Sjmallett    /* Check to see if what we want to write is not contiguous, and limit ourselves to the contiguous block*/
165210284Sjmallett    if (wr_idx + bytes_to_write >= console_buffer_size)
166210284Sjmallett        bytes_to_write = console_buffer_size - wr_idx;
167210284Sjmallett
168210284Sjmallett//    printf("Attempting to write %d bytes, (buf size: %d)\n", bytes_to_write, write_reqest_size);
169210284Sjmallett
170210284Sjmallett    octeon_pci_write_mem(base_addr + wr_idx, buffer, bytes_to_write, OCTEON_PCI_ENDIAN_64BIT_SWAP);
171210284Sjmallett    octeon_write_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index), (wr_idx + bytes_to_write)%console_buffer_size);
172210284Sjmallett
173210284Sjmallett    return bytes_to_write;
174210284Sjmallett
175210284Sjmallett}
176210284Sjmallett
177210284Sjmallettint octeon_pci_console_host_read(uint64_t console_desc_addr, unsigned int console_num, char * buffer, int buf_size, uint32_t flags)
178210284Sjmallett{
179210284Sjmallett    if (!console_desc_addr)
180210284Sjmallett        return -1;
181210284Sjmallett
182210284Sjmallett    /* Get global pci console information and look up specific console structure. */
183210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
184210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
185210284Sjmallett    if (console_num >= num_consoles)
186210284Sjmallett    {
187210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
188210284Sjmallett        return(-1);
189210284Sjmallett    }
190210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
191210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
192210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
193210284Sjmallett
194210284Sjmallett    /* Check to see if any data is available */
195210284Sjmallett    uint32_t rd_idx, wr_idx;
196210284Sjmallett    uint64_t base_addr;
197210284Sjmallett
198210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, output_base_addr));
199210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index));
200210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_write_index));
201210284Sjmallett
202210284Sjmallett//    printf("Read buffer base: 0x%llx, rd: %d(0x%x), wr: %d(0x%x)\n", (long long)base_addr, rd_idx, rd_idx, wr_idx, wr_idx);
203210284Sjmallett    int bytes_to_read = octeon_pci_console_buffer_avail_bytes(console_buffer_size, wr_idx, rd_idx);
204210284Sjmallett    if (bytes_to_read <= 0)
205210284Sjmallett        return bytes_to_read;
206210284Sjmallett
207210284Sjmallett
208210284Sjmallett    bytes_to_read = MIN(bytes_to_read, buf_size);
209210284Sjmallett    /* Check to see if what we want to read is not contiguous, and limit ourselves to the contiguous block*/
210210284Sjmallett    if (rd_idx + bytes_to_read >= console_buffer_size)
211210284Sjmallett        bytes_to_read = console_buffer_size - rd_idx;
212210284Sjmallett
213210284Sjmallett
214210284Sjmallett    octeon_pci_read_mem(buffer, base_addr + rd_idx, bytes_to_read,OCTEON_PCI_ENDIAN_64BIT_SWAP);
215210284Sjmallett    octeon_write_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index), (rd_idx + bytes_to_read)%console_buffer_size);
216210284Sjmallett
217210284Sjmallett    return bytes_to_read;
218210284Sjmallett}
219210284Sjmallett
220210284Sjmallett
221210284Sjmallettint octeon_pci_console_host_write_avail(uint64_t console_desc_addr, unsigned int console_num)
222210284Sjmallett{
223210284Sjmallett    if (!console_desc_addr)
224210284Sjmallett        return -1;
225210284Sjmallett
226210284Sjmallett    /* Get global pci console information and look up specific console structure. */
227210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
228210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
229210284Sjmallett    if (console_num >= num_consoles)
230210284Sjmallett    {
231210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
232210284Sjmallett        return -1;
233210284Sjmallett    }
234210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
235210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
236210284Sjmallett
237210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
238210284Sjmallett    /* Check to see if any data is available */
239210284Sjmallett    uint32_t rd_idx, wr_idx;
240210284Sjmallett    uint64_t base_addr;
241210284Sjmallett
242210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, input_base_addr));
243210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_read_index));
244210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index));
245210284Sjmallett
246210284Sjmallett//    printf("Input base: 0x%llx, rd: %d(0x%x), wr: %d(0x%x)\n", (long long)base_addr, rd_idx, rd_idx, wr_idx, wr_idx);
247210284Sjmallett    return octeon_pci_console_buffer_free_bytes(console_buffer_size, wr_idx, rd_idx);
248210284Sjmallett}
249210284Sjmallett
250210284Sjmallett
251210284Sjmallettint octeon_pci_console_host_read_avail(uint64_t console_desc_addr, unsigned int console_num)
252210284Sjmallett{
253210284Sjmallett    if (!console_desc_addr)
254210284Sjmallett        return -1;
255210284Sjmallett
256210284Sjmallett    /* Get global pci console information and look up specific console structure. */
257210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
258210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
259210284Sjmallett    if (console_num >= num_consoles)
260210284Sjmallett    {
261210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
262210284Sjmallett        return(-1);
263210284Sjmallett    }
264210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
265210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
266210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
267210284Sjmallett
268210284Sjmallett    /* Check to see if any data is available */
269210284Sjmallett    uint32_t rd_idx, wr_idx;
270210284Sjmallett    uint64_t base_addr;
271210284Sjmallett
272210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, output_base_addr));
273210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index));
274210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_write_index));
275210284Sjmallett
276210284Sjmallett//    printf("Read buffer base: 0x%llx, rd: %d(0x%x), wr: %d(0x%x)\n", (long long)base_addr, rd_idx, rd_idx, wr_idx, wr_idx);
277210284Sjmallett    return octeon_pci_console_buffer_avail_bytes(console_buffer_size, wr_idx, rd_idx);
278210284Sjmallett}
279210284Sjmallett
280210284Sjmallett
281210284Sjmallett#endif /* TARGET_HOST */
282210284Sjmallett
283210284Sjmallett
284210284Sjmallett
285210284Sjmallett
286210284Sjmallett
287210284Sjmallett
288210284Sjmallett/* This code is only available in a kernel or CVMX standalone. It can't be used
289210284Sjmallett    from userspace */
290242952Sjmallett#if (!defined(CONFIG_OCTEON_U_BOOT) && (!defined(__linux__) || defined(__KERNEL__))) || (defined(CONFIG_OCTEON_U_BOOT) && (defined(CFG_PCI_CONSOLE) || defined(CONFIG_SYS_PCI_CONSOLE))) || defined(CVMX_BUILD_FOR_LINUX_KERNEL)
291210284Sjmallett
292210284Sjmallettstatic octeon_pci_console_t *octeon_pci_console_get_ptr(uint64_t console_desc_addr, unsigned int console_num)
293210284Sjmallett{
294210284Sjmallett    octeon_pci_console_desc_t *cons_desc_ptr;
295210284Sjmallett
296210284Sjmallett    if (!console_desc_addr)
297210284Sjmallett        return NULL;
298210284Sjmallett
299210284Sjmallett    cons_desc_ptr = (octeon_pci_console_desc_t *)cvmx_phys_to_ptr(console_desc_addr);
300210284Sjmallett    if (console_num >= cons_desc_ptr->num_consoles)
301210284Sjmallett        return NULL;
302210284Sjmallett
303210284Sjmallett    return (octeon_pci_console_t *)cvmx_phys_to_ptr(cons_desc_ptr->console_addr_array[console_num]);
304210284Sjmallett}
305210284Sjmallett
306210284Sjmallett
307210284Sjmallettint octeon_pci_console_write(uint64_t console_desc_addr, unsigned int console_num, const char * buffer, int bytes_to_write, uint32_t flags)
308210284Sjmallett{
309210284Sjmallett    octeon_pci_console_t *cons_ptr;
310210284Sjmallett    cvmx_spinlock_t *lock;
311210284Sjmallett    int bytes_available;
312210284Sjmallett    char *buf_ptr;
313210284Sjmallett    int bytes_written;
314210284Sjmallett
315210284Sjmallett    cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
316210284Sjmallett    if (!cons_ptr)
317210284Sjmallett        return -1;
318210284Sjmallett
319210284Sjmallett    lock = (cvmx_spinlock_t *)&cons_ptr->lock;
320210284Sjmallett
321210284Sjmallett    buf_ptr = (char*)cvmx_phys_to_ptr(cons_ptr->output_base_addr);
322210284Sjmallett    bytes_written = 0;
323210284Sjmallett    cvmx_spinlock_lock(lock);
324210284Sjmallett    while (bytes_to_write > 0)
325210284Sjmallett    {
326210284Sjmallett        bytes_available = octeon_pci_console_buffer_free_bytes(cons_ptr->buf_size, cons_ptr->output_write_index, cons_ptr->output_read_index);
327210284Sjmallett//        printf("Console %d has %d bytes available for writes\n", console_num, bytes_available);
328210284Sjmallett        if (bytes_available > 0)
329210284Sjmallett        {
330210284Sjmallett            int write_size = MIN(bytes_available, bytes_to_write);
331210284Sjmallett            /* Limit ourselves to what we can output in a contiguous block */
332210284Sjmallett            if (cons_ptr->output_write_index + write_size >= cons_ptr->buf_size)
333210284Sjmallett                write_size = cons_ptr->buf_size - cons_ptr->output_write_index;
334210284Sjmallett
335210284Sjmallett            memcpy(buf_ptr + cons_ptr->output_write_index, buffer + bytes_written, write_size);
336210284Sjmallett            CVMX_SYNCW;  /* Make sure data is visible before changing write index */
337210284Sjmallett            cons_ptr->output_write_index = (cons_ptr->output_write_index + write_size)%cons_ptr->buf_size;
338210284Sjmallett            bytes_to_write -= write_size;
339210284Sjmallett            bytes_written += write_size;
340210284Sjmallett        }
341210284Sjmallett        else if (bytes_available == 0)
342210284Sjmallett        {
343210284Sjmallett            /* Check to see if we should wait for room, or return after a partial write */
344210284Sjmallett            if (flags & OCT_PCI_CON_FLAG_NONBLOCK)
345210284Sjmallett                goto done;
346210284Sjmallett
347232812Sjmallett#ifdef __U_BOOT__
348232812Sjmallett            WATCHDOG_RESET();
349232812Sjmallett#endif
350210284Sjmallett            cvmx_wait(1000000);  /* Delay if we are spinning */
351210284Sjmallett        }
352210284Sjmallett        else
353210284Sjmallett        {
354210284Sjmallett            bytes_written = -1;
355210284Sjmallett            goto done;
356210284Sjmallett        }
357210284Sjmallett    }
358210284Sjmallett
359210284Sjmallettdone:
360210284Sjmallett    cvmx_spinlock_unlock(lock);
361210284Sjmallett    return(bytes_written);
362210284Sjmallett}
363210284Sjmallett
364210284Sjmallettint octeon_pci_console_read(uint64_t console_desc_addr, unsigned int console_num, char * buffer, int buffer_size, uint32_t flags)
365210284Sjmallett{
366210284Sjmallett    int bytes_available;
367210284Sjmallett    char *buf_ptr;
368210284Sjmallett    cvmx_spinlock_t *lock;
369210284Sjmallett    int bytes_read;
370210284Sjmallett    int read_size;
371210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
372210284Sjmallett    if (!cons_ptr)
373210284Sjmallett        return -1;
374210284Sjmallett
375210284Sjmallett    buf_ptr = (char*)cvmx_phys_to_ptr(cons_ptr->input_base_addr);
376210284Sjmallett
377210284Sjmallett    bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
378210284Sjmallett    if (bytes_available < 0)
379210284Sjmallett        return bytes_available;
380210284Sjmallett
381210284Sjmallett    lock = (cvmx_spinlock_t *)&cons_ptr->lock;
382210284Sjmallett    cvmx_spinlock_lock(lock);
383210284Sjmallett
384210284Sjmallett    if (!(flags & OCT_PCI_CON_FLAG_NONBLOCK))
385210284Sjmallett    {
386210284Sjmallett        /* Wait for some data to be available */
387210284Sjmallett        while (0 == (bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index)))
388232812Sjmallett        {
389210284Sjmallett            cvmx_wait(1000000);
390232812Sjmallett#ifdef __U_BOOT__
391232812Sjmallett            WATCHDOG_RESET();
392232812Sjmallett#endif
393232812Sjmallett        }
394210284Sjmallett    }
395210284Sjmallett
396210284Sjmallett    bytes_read = 0;
397210284Sjmallett//        printf("Console %d has %d bytes available for writes\n", console_num, bytes_available);
398210284Sjmallett
399210284Sjmallett    /* Don't overflow the buffer passed to us */
400210284Sjmallett    read_size = MIN(bytes_available, buffer_size);
401210284Sjmallett
402210284Sjmallett    /* Limit ourselves to what we can input in a contiguous block */
403210284Sjmallett    if (cons_ptr->input_read_index + read_size >= cons_ptr->buf_size)
404210284Sjmallett        read_size = cons_ptr->buf_size - cons_ptr->input_read_index;
405210284Sjmallett
406210284Sjmallett    memcpy(buffer, buf_ptr + cons_ptr->input_read_index, read_size);
407210284Sjmallett    cons_ptr->input_read_index = (cons_ptr->input_read_index + read_size)%cons_ptr->buf_size;
408210284Sjmallett    bytes_read += read_size;
409210284Sjmallett
410210284Sjmallett    cvmx_spinlock_unlock(lock);
411210284Sjmallett    return(bytes_read);
412210284Sjmallett}
413210284Sjmallett
414210284Sjmallett
415210284Sjmallettint octeon_pci_console_write_avail(uint64_t console_desc_addr, unsigned int console_num)
416210284Sjmallett{
417210284Sjmallett    int bytes_available;
418210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
419210284Sjmallett    if (!cons_ptr)
420210284Sjmallett        return -1;
421210284Sjmallett
422210284Sjmallett    bytes_available = octeon_pci_console_buffer_free_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
423210284Sjmallett    if (bytes_available >= 0)
424210284Sjmallett        return(bytes_available);
425210284Sjmallett    else
426210284Sjmallett        return 0;
427210284Sjmallett}
428210284Sjmallett
429210284Sjmallett
430210284Sjmallettint octeon_pci_console_read_avail(uint64_t console_desc_addr, unsigned int console_num)
431210284Sjmallett{
432210284Sjmallett    int bytes_available;
433210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
434210284Sjmallett    if (!cons_ptr)
435210284Sjmallett        return -1;
436210284Sjmallett
437210284Sjmallett    bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
438210284Sjmallett    if (bytes_available >= 0)
439210284Sjmallett        return(bytes_available);
440210284Sjmallett    else
441210284Sjmallett        return 0;
442210284Sjmallett}
443210284Sjmallett
444210284Sjmallett#endif
445210284Sjmallett
446210284Sjmallett
447210284Sjmallett/* This code can only be used in the bootloader */
448232812Sjmallett#if defined(CONFIG_OCTEON_U_BOOT) && (defined(CFG_PCI_CONSOLE) || defined(CONFIG_SYS_PCI_CONSOLE))
449210284Sjmallettuint64_t  octeon_pci_console_init(int num_consoles, int buffer_size)
450210284Sjmallett{
451210284Sjmallett    octeon_pci_console_desc_t *cons_desc_ptr;
452210284Sjmallett    octeon_pci_console_t *cons_ptr;
453210284Sjmallett
454210284Sjmallett    /* Compute size required for pci console structure */
455210284Sjmallett    int alloc_size = num_consoles * (buffer_size * 2 + sizeof(octeon_pci_console_t) + sizeof(uint64_t)) + sizeof(octeon_pci_console_desc_t);
456210284Sjmallett
457210284Sjmallett    /* Allocate memory for the consoles.  This must be in the range addresssible by the bootloader.
458210284Sjmallett    ** Try to do so in a manner which minimizes fragmentation.  We try to put it at the top of DDR0 or bottom of
459210284Sjmallett    ** DDR2 first, and only do generic allocation if those fail */
460232812Sjmallett    int64_t console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, OCTEON_DDR0_SIZE - alloc_size - 128, OCTEON_DDR0_SIZE, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
461210284Sjmallett    if (console_block_addr < 0)
462232812Sjmallett        console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, OCTEON_DDR2_BASE + 1, OCTEON_DDR2_BASE + alloc_size + 128, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
463210284Sjmallett    if (console_block_addr < 0)
464210284Sjmallett        console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, 0, 0x7fffffff, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
465210284Sjmallett    if (console_block_addr < 0)
466210284Sjmallett        return 0;
467210284Sjmallett
468210284Sjmallett    cons_desc_ptr = (void *)(uint32_t)console_block_addr;
469210284Sjmallett
470210284Sjmallett    memset(cons_desc_ptr, 0, alloc_size);  /* Clear entire alloc'ed memory */
471210284Sjmallett
472210284Sjmallett    cons_desc_ptr->lock = 1; /* initialize as locked until we are done */
473210284Sjmallett    CVMX_SYNCW;
474210284Sjmallett    cons_desc_ptr->num_consoles = num_consoles;
475210284Sjmallett    cons_desc_ptr->flags = 0;
476210284Sjmallett    cons_desc_ptr->major_version = OCTEON_PCI_CONSOLE_MAJOR_VERSION;
477210284Sjmallett    cons_desc_ptr->minor_version = OCTEON_PCI_CONSOLE_MINOR_VERSION;
478210284Sjmallett
479210284Sjmallett    int i;
480210284Sjmallett    uint64_t avail_addr = console_block_addr + sizeof(octeon_pci_console_desc_t) + num_consoles * sizeof(uint64_t);
481210284Sjmallett    for (i = 0; i < num_consoles;i++)
482210284Sjmallett    {
483210284Sjmallett        cons_desc_ptr->console_addr_array[i] = avail_addr;
484210284Sjmallett        cons_ptr = (void *)(uint32_t)cons_desc_ptr->console_addr_array[i];
485210284Sjmallett        avail_addr += sizeof(octeon_pci_console_t);
486210284Sjmallett        cons_ptr->input_base_addr = avail_addr;
487210284Sjmallett        avail_addr += buffer_size;
488210284Sjmallett        cons_ptr->output_base_addr = avail_addr;
489210284Sjmallett        avail_addr += buffer_size;
490210284Sjmallett        cons_ptr->buf_size = buffer_size;
491210284Sjmallett    }
492210284Sjmallett    CVMX_SYNCW;
493210284Sjmallett    cons_desc_ptr->lock = 0;
494210284Sjmallett
495210284Sjmallett    return console_block_addr;
496210284Sjmallett
497210284Sjmallett
498210284Sjmallett}
499210284Sjmallett#endif
500