octeon-pci-console.c revision 215990
1210284Sjmallett/***********************license start***************
2215990Sjmallett * Copyright (c) 2003-2010  Cavium Networks (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
18215990Sjmallett *   * Neither the name of Cavium Networks 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"
29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM  NETWORKS 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"
60210284Sjmallett#define	MIN(a,b) (((a)<(b))?(a):(b))
61210284Sjmallett
62210284Sjmallett#include "cvmx-bootmem.h"
63215990Sjmallett#include "octeon-pci-console.h"
64210284Sjmallett#endif
65210284Sjmallett
66210284Sjmallett
67210284Sjmallett#if defined(__linux__) && !defined(__KERNEL__) && !defined(OCTEON_TARGET)
68210284Sjmallett#include "octeon-pci.h"
69210284Sjmallett#endif
70210284Sjmallett
71210284Sjmallett
72210284Sjmallett/* The following code is only used in standalone CVMX applications. It does
73210284Sjmallett    not apply for kernel or Linux programming */
74210284Sjmallett#if defined(OCTEON_TARGET) && !defined(__linux__)
75210284Sjmallett
76210284Sjmallettstatic int cvmx_pci_console_num = 0;
77210284Sjmallettstatic int per_core_pci_consoles = 0;
78210284Sjmallettstatic uint64_t pci_console_desc_addr = 0;
79210284Sjmallett/* This function for simple executive internal use only - do not use in any application */
80210284Sjmallettint  __cvmx_pci_console_write (int fd, char *buf, int nbytes)
81210284Sjmallett{
82210284Sjmallett    int console_num;
83210284Sjmallett    if (fd >= 0x10000000)
84210284Sjmallett    {
85210284Sjmallett        console_num = fd & 0xFFFF;
86210284Sjmallett    }
87210284Sjmallett    else if (per_core_pci_consoles)
88210284Sjmallett    {
89210284Sjmallett        console_num = cvmx_get_core_num();
90210284Sjmallett    }
91210284Sjmallett    else
92210284Sjmallett        console_num = cvmx_pci_console_num;
93210284Sjmallett
94210284Sjmallett    if (!pci_console_desc_addr)
95210284Sjmallett    {
96215990Sjmallett        const cvmx_bootmem_named_block_desc_t *block_desc = cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME);
97210284Sjmallett        pci_console_desc_addr = block_desc->base_addr;
98210284Sjmallett    }
99210284Sjmallett
100210284Sjmallett
101210284Sjmallett    return octeon_pci_console_write(pci_console_desc_addr, console_num, buf, nbytes, 0);
102210284Sjmallett
103210284Sjmallett}
104210284Sjmallett
105210284Sjmallett#endif
106210284Sjmallett
107210284Sjmallett
108210284Sjmallett#if !defined(CONFIG_OCTEON_U_BOOT) || (defined(CONFIG_OCTEON_U_BOOT) && defined(CFG_PCI_CONSOLE))
109210284Sjmallettint octeon_pci_console_buffer_free_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx)
110210284Sjmallett{
111210284Sjmallett    if (rd_idx >= buffer_size || wr_idx >= buffer_size)
112210284Sjmallett        return -1;
113210284Sjmallett
114210284Sjmallett    return (((buffer_size -1) - (wr_idx - rd_idx))%buffer_size);
115210284Sjmallett}
116210284Sjmallettint octeon_pci_console_buffer_avail_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx)
117210284Sjmallett{
118210284Sjmallett    if (rd_idx >= buffer_size || wr_idx >= buffer_size)
119210284Sjmallett        return -1;
120210284Sjmallett
121210284Sjmallett    return (buffer_size - 1 - octeon_pci_console_buffer_free_bytes(buffer_size, wr_idx, rd_idx));
122210284Sjmallett}
123210284Sjmallett#endif
124210284Sjmallett
125210284Sjmallett
126210284Sjmallett
127210284Sjmallett/* The following code is only used under Linux userspace when you are using
128210284Sjmallett    CVMX */
129210284Sjmallett#if defined(__linux__) && !defined(__KERNEL__) && !defined(OCTEON_TARGET)
130210284Sjmallettint octeon_pci_console_host_write(uint64_t console_desc_addr, unsigned int console_num, const char * buffer, int write_reqest_size, uint32_t flags)
131210284Sjmallett{
132210284Sjmallett    if (!console_desc_addr)
133210284Sjmallett        return -1;
134210284Sjmallett
135210284Sjmallett    /* Get global pci console information and look up specific console structure. */
136210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
137210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
138210284Sjmallett    if (console_num >= num_consoles)
139210284Sjmallett    {
140210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
141210284Sjmallett        return(-1);
142210284Sjmallett    }
143210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
144210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
145210284Sjmallett
146210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
147210284Sjmallett    /* Check to see if any data is available */
148210284Sjmallett    uint32_t rd_idx, wr_idx;
149210284Sjmallett    uint64_t base_addr;
150210284Sjmallett
151210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, input_base_addr));
152210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_read_index));
153210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index));
154210284Sjmallett
155210284Sjmallett//    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);
156210284Sjmallett    int bytes_to_write = octeon_pci_console_buffer_free_bytes(console_buffer_size, wr_idx, rd_idx);
157210284Sjmallett    if (bytes_to_write <= 0)
158210284Sjmallett        return bytes_to_write;
159210284Sjmallett    bytes_to_write = MIN(bytes_to_write, write_reqest_size);
160210284Sjmallett    /* Check to see if what we want to write is not contiguous, and limit ourselves to the contiguous block*/
161210284Sjmallett    if (wr_idx + bytes_to_write >= console_buffer_size)
162210284Sjmallett        bytes_to_write = console_buffer_size - wr_idx;
163210284Sjmallett
164210284Sjmallett//    printf("Attempting to write %d bytes, (buf size: %d)\n", bytes_to_write, write_reqest_size);
165210284Sjmallett
166210284Sjmallett    octeon_pci_write_mem(base_addr + wr_idx, buffer, bytes_to_write, OCTEON_PCI_ENDIAN_64BIT_SWAP);
167210284Sjmallett    octeon_write_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index), (wr_idx + bytes_to_write)%console_buffer_size);
168210284Sjmallett
169210284Sjmallett    return bytes_to_write;
170210284Sjmallett
171210284Sjmallett}
172210284Sjmallett
173210284Sjmallettint octeon_pci_console_host_read(uint64_t console_desc_addr, unsigned int console_num, char * buffer, int buf_size, uint32_t flags)
174210284Sjmallett{
175210284Sjmallett    if (!console_desc_addr)
176210284Sjmallett        return -1;
177210284Sjmallett
178210284Sjmallett    /* Get global pci console information and look up specific console structure. */
179210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
180210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
181210284Sjmallett    if (console_num >= num_consoles)
182210284Sjmallett    {
183210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
184210284Sjmallett        return(-1);
185210284Sjmallett    }
186210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
187210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
188210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
189210284Sjmallett
190210284Sjmallett    /* Check to see if any data is available */
191210284Sjmallett    uint32_t rd_idx, wr_idx;
192210284Sjmallett    uint64_t base_addr;
193210284Sjmallett
194210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, output_base_addr));
195210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index));
196210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_write_index));
197210284Sjmallett
198210284Sjmallett//    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);
199210284Sjmallett    int bytes_to_read = octeon_pci_console_buffer_avail_bytes(console_buffer_size, wr_idx, rd_idx);
200210284Sjmallett    if (bytes_to_read <= 0)
201210284Sjmallett        return bytes_to_read;
202210284Sjmallett
203210284Sjmallett
204210284Sjmallett    bytes_to_read = MIN(bytes_to_read, buf_size);
205210284Sjmallett    /* Check to see if what we want to read is not contiguous, and limit ourselves to the contiguous block*/
206210284Sjmallett    if (rd_idx + bytes_to_read >= console_buffer_size)
207210284Sjmallett        bytes_to_read = console_buffer_size - rd_idx;
208210284Sjmallett
209210284Sjmallett
210210284Sjmallett    octeon_pci_read_mem(buffer, base_addr + rd_idx, bytes_to_read,OCTEON_PCI_ENDIAN_64BIT_SWAP);
211210284Sjmallett    octeon_write_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index), (rd_idx + bytes_to_read)%console_buffer_size);
212210284Sjmallett
213210284Sjmallett    return bytes_to_read;
214210284Sjmallett}
215210284Sjmallett
216210284Sjmallett
217210284Sjmallettint octeon_pci_console_host_write_avail(uint64_t console_desc_addr, unsigned int console_num)
218210284Sjmallett{
219210284Sjmallett    if (!console_desc_addr)
220210284Sjmallett        return -1;
221210284Sjmallett
222210284Sjmallett    /* Get global pci console information and look up specific console structure. */
223210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
224210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
225210284Sjmallett    if (console_num >= num_consoles)
226210284Sjmallett    {
227210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
228210284Sjmallett        return -1;
229210284Sjmallett    }
230210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
231210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
232210284Sjmallett
233210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
234210284Sjmallett    /* Check to see if any data is available */
235210284Sjmallett    uint32_t rd_idx, wr_idx;
236210284Sjmallett    uint64_t base_addr;
237210284Sjmallett
238210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, input_base_addr));
239210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_read_index));
240210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, input_write_index));
241210284Sjmallett
242210284Sjmallett//    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);
243210284Sjmallett    return octeon_pci_console_buffer_free_bytes(console_buffer_size, wr_idx, rd_idx);
244210284Sjmallett}
245210284Sjmallett
246210284Sjmallett
247210284Sjmallettint octeon_pci_console_host_read_avail(uint64_t console_desc_addr, unsigned int console_num)
248210284Sjmallett{
249210284Sjmallett    if (!console_desc_addr)
250210284Sjmallett        return -1;
251210284Sjmallett
252210284Sjmallett    /* Get global pci console information and look up specific console structure. */
253210284Sjmallett    uint32_t num_consoles = octeon_read_mem32(console_desc_addr + offsetof(octeon_pci_console_desc_t, num_consoles));
254210284Sjmallett//    printf("Num consoles: %d, buf size: %d\n", num_consoles, console_buffer_size);
255210284Sjmallett    if (console_num >= num_consoles)
256210284Sjmallett    {
257210284Sjmallett        printf("ERROR: attempting to read non-existant console: %d\n", console_num);
258210284Sjmallett        return(-1);
259210284Sjmallett    }
260210284Sjmallett    uint64_t console_addr = octeon_read_mem64(console_desc_addr + offsetof(octeon_pci_console_desc_t, console_addr_array) + console_num *8);
261210284Sjmallett    uint32_t console_buffer_size = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, buf_size));
262210284Sjmallett//    printf("Console %d is at 0x%llx\n", console_num, (long long)console_addr);
263210284Sjmallett
264210284Sjmallett    /* Check to see if any data is available */
265210284Sjmallett    uint32_t rd_idx, wr_idx;
266210284Sjmallett    uint64_t base_addr;
267210284Sjmallett
268210284Sjmallett    base_addr = octeon_read_mem64(console_addr + offsetof(octeon_pci_console_t, output_base_addr));
269210284Sjmallett    rd_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_read_index));
270210284Sjmallett    wr_idx = octeon_read_mem32(console_addr + offsetof(octeon_pci_console_t, output_write_index));
271210284Sjmallett
272210284Sjmallett//    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);
273210284Sjmallett    return octeon_pci_console_buffer_avail_bytes(console_buffer_size, wr_idx, rd_idx);
274210284Sjmallett}
275210284Sjmallett
276210284Sjmallett
277210284Sjmallett#endif /* TARGET_HOST */
278210284Sjmallett
279210284Sjmallett
280210284Sjmallett
281210284Sjmallett
282210284Sjmallett
283210284Sjmallett
284210284Sjmallett/* This code is only available in a kernel or CVMX standalone. It can't be used
285210284Sjmallett    from userspace */
286210284Sjmallett#if (!defined(CONFIG_OCTEON_U_BOOT) && (!defined(__linux__) || defined(__KERNEL__))) || (defined(CONFIG_OCTEON_U_BOOT) && defined(CFG_PCI_CONSOLE))
287210284Sjmallett
288210284Sjmallettstatic octeon_pci_console_t *octeon_pci_console_get_ptr(uint64_t console_desc_addr, unsigned int console_num)
289210284Sjmallett{
290210284Sjmallett    octeon_pci_console_desc_t *cons_desc_ptr;
291210284Sjmallett
292210284Sjmallett    if (!console_desc_addr)
293210284Sjmallett        return NULL;
294210284Sjmallett
295210284Sjmallett    cons_desc_ptr = (octeon_pci_console_desc_t *)cvmx_phys_to_ptr(console_desc_addr);
296210284Sjmallett    if (console_num >= cons_desc_ptr->num_consoles)
297210284Sjmallett        return NULL;
298210284Sjmallett
299210284Sjmallett    return (octeon_pci_console_t *)cvmx_phys_to_ptr(cons_desc_ptr->console_addr_array[console_num]);
300210284Sjmallett}
301210284Sjmallett
302210284Sjmallett
303210284Sjmallettint octeon_pci_console_write(uint64_t console_desc_addr, unsigned int console_num, const char * buffer, int bytes_to_write, uint32_t flags)
304210284Sjmallett{
305210284Sjmallett    octeon_pci_console_t *cons_ptr;
306210284Sjmallett    cvmx_spinlock_t *lock;
307210284Sjmallett    int bytes_available;
308210284Sjmallett    char *buf_ptr;
309210284Sjmallett    int bytes_written;
310210284Sjmallett
311210284Sjmallett    cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
312210284Sjmallett    if (!cons_ptr)
313210284Sjmallett        return -1;
314210284Sjmallett
315210284Sjmallett    lock = (cvmx_spinlock_t *)&cons_ptr->lock;
316210284Sjmallett
317210284Sjmallett    buf_ptr = (char*)cvmx_phys_to_ptr(cons_ptr->output_base_addr);
318210284Sjmallett    bytes_written = 0;
319210284Sjmallett    cvmx_spinlock_lock(lock);
320210284Sjmallett    while (bytes_to_write > 0)
321210284Sjmallett    {
322210284Sjmallett        bytes_available = octeon_pci_console_buffer_free_bytes(cons_ptr->buf_size, cons_ptr->output_write_index, cons_ptr->output_read_index);
323210284Sjmallett//        printf("Console %d has %d bytes available for writes\n", console_num, bytes_available);
324210284Sjmallett        if (bytes_available > 0)
325210284Sjmallett        {
326210284Sjmallett            int write_size = MIN(bytes_available, bytes_to_write);
327210284Sjmallett            /* Limit ourselves to what we can output in a contiguous block */
328210284Sjmallett            if (cons_ptr->output_write_index + write_size >= cons_ptr->buf_size)
329210284Sjmallett                write_size = cons_ptr->buf_size - cons_ptr->output_write_index;
330210284Sjmallett
331210284Sjmallett            memcpy(buf_ptr + cons_ptr->output_write_index, buffer + bytes_written, write_size);
332210284Sjmallett            CVMX_SYNCW;  /* Make sure data is visible before changing write index */
333210284Sjmallett            cons_ptr->output_write_index = (cons_ptr->output_write_index + write_size)%cons_ptr->buf_size;
334210284Sjmallett            bytes_to_write -= write_size;
335210284Sjmallett            bytes_written += write_size;
336210284Sjmallett        }
337210284Sjmallett        else if (bytes_available == 0)
338210284Sjmallett        {
339210284Sjmallett            /* Check to see if we should wait for room, or return after a partial write */
340210284Sjmallett            if (flags & OCT_PCI_CON_FLAG_NONBLOCK)
341210284Sjmallett                goto done;
342210284Sjmallett
343210284Sjmallett            cvmx_wait(1000000);  /* Delay if we are spinning */
344210284Sjmallett        }
345210284Sjmallett        else
346210284Sjmallett        {
347210284Sjmallett            bytes_written = -1;
348210284Sjmallett            goto done;
349210284Sjmallett        }
350210284Sjmallett    }
351210284Sjmallett
352210284Sjmallettdone:
353210284Sjmallett    cvmx_spinlock_unlock(lock);
354210284Sjmallett    return(bytes_written);
355210284Sjmallett}
356210284Sjmallett
357210284Sjmallettint octeon_pci_console_read(uint64_t console_desc_addr, unsigned int console_num, char * buffer, int buffer_size, uint32_t flags)
358210284Sjmallett{
359210284Sjmallett    int bytes_available;
360210284Sjmallett    char *buf_ptr;
361210284Sjmallett    cvmx_spinlock_t *lock;
362210284Sjmallett    int bytes_read;
363210284Sjmallett    int read_size;
364210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
365210284Sjmallett    if (!cons_ptr)
366210284Sjmallett        return -1;
367210284Sjmallett
368210284Sjmallett    buf_ptr = (char*)cvmx_phys_to_ptr(cons_ptr->input_base_addr);
369210284Sjmallett
370210284Sjmallett    bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
371210284Sjmallett    if (bytes_available < 0)
372210284Sjmallett        return bytes_available;
373210284Sjmallett
374210284Sjmallett    lock = (cvmx_spinlock_t *)&cons_ptr->lock;
375210284Sjmallett    cvmx_spinlock_lock(lock);
376210284Sjmallett
377210284Sjmallett    if (!(flags & OCT_PCI_CON_FLAG_NONBLOCK))
378210284Sjmallett    {
379210284Sjmallett        /* Wait for some data to be available */
380210284Sjmallett        while (0 == (bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index)))
381210284Sjmallett            cvmx_wait(1000000);
382210284Sjmallett    }
383210284Sjmallett
384210284Sjmallett    bytes_read = 0;
385210284Sjmallett//        printf("Console %d has %d bytes available for writes\n", console_num, bytes_available);
386210284Sjmallett
387210284Sjmallett    /* Don't overflow the buffer passed to us */
388210284Sjmallett    read_size = MIN(bytes_available, buffer_size);
389210284Sjmallett
390210284Sjmallett    /* Limit ourselves to what we can input in a contiguous block */
391210284Sjmallett    if (cons_ptr->input_read_index + read_size >= cons_ptr->buf_size)
392210284Sjmallett        read_size = cons_ptr->buf_size - cons_ptr->input_read_index;
393210284Sjmallett
394210284Sjmallett    memcpy(buffer, buf_ptr + cons_ptr->input_read_index, read_size);
395210284Sjmallett    cons_ptr->input_read_index = (cons_ptr->input_read_index + read_size)%cons_ptr->buf_size;
396210284Sjmallett    bytes_read += read_size;
397210284Sjmallett
398210284Sjmallett    cvmx_spinlock_unlock(lock);
399210284Sjmallett    return(bytes_read);
400210284Sjmallett}
401210284Sjmallett
402210284Sjmallett
403210284Sjmallettint octeon_pci_console_write_avail(uint64_t console_desc_addr, unsigned int console_num)
404210284Sjmallett{
405210284Sjmallett    int bytes_available;
406210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
407210284Sjmallett    if (!cons_ptr)
408210284Sjmallett        return -1;
409210284Sjmallett
410210284Sjmallett    bytes_available = octeon_pci_console_buffer_free_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
411210284Sjmallett    if (bytes_available >= 0)
412210284Sjmallett        return(bytes_available);
413210284Sjmallett    else
414210284Sjmallett        return 0;
415210284Sjmallett}
416210284Sjmallett
417210284Sjmallett
418210284Sjmallettint octeon_pci_console_read_avail(uint64_t console_desc_addr, unsigned int console_num)
419210284Sjmallett{
420210284Sjmallett    int bytes_available;
421210284Sjmallett    octeon_pci_console_t *cons_ptr = octeon_pci_console_get_ptr(console_desc_addr, console_num);
422210284Sjmallett    if (!cons_ptr)
423210284Sjmallett        return -1;
424210284Sjmallett
425210284Sjmallett    bytes_available = octeon_pci_console_buffer_avail_bytes(cons_ptr->buf_size, cons_ptr->input_write_index, cons_ptr->input_read_index);
426210284Sjmallett    if (bytes_available >= 0)
427210284Sjmallett        return(bytes_available);
428210284Sjmallett    else
429210284Sjmallett        return 0;
430210284Sjmallett}
431210284Sjmallett
432210284Sjmallett#endif
433210284Sjmallett
434210284Sjmallett
435210284Sjmallett/* This code can only be used in the bootloader */
436210284Sjmallett#if defined(CONFIG_OCTEON_U_BOOT) && defined(CFG_PCI_CONSOLE)
437210284Sjmallett#define DDR0_TOP        0x10000000
438210284Sjmallett#define DDR2_BASE       0x20000000
439210284Sjmallettuint64_t  octeon_pci_console_init(int num_consoles, int buffer_size)
440210284Sjmallett{
441210284Sjmallett    octeon_pci_console_desc_t *cons_desc_ptr;
442210284Sjmallett    octeon_pci_console_t *cons_ptr;
443210284Sjmallett
444210284Sjmallett    /* Compute size required for pci console structure */
445210284Sjmallett    int alloc_size = num_consoles * (buffer_size * 2 + sizeof(octeon_pci_console_t) + sizeof(uint64_t)) + sizeof(octeon_pci_console_desc_t);
446210284Sjmallett
447210284Sjmallett    /* Allocate memory for the consoles.  This must be in the range addresssible by the bootloader.
448210284Sjmallett    ** Try to do so in a manner which minimizes fragmentation.  We try to put it at the top of DDR0 or bottom of
449210284Sjmallett    ** DDR2 first, and only do generic allocation if those fail */
450210284Sjmallett    int64_t console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, DDR0_TOP - alloc_size - 128, DDR0_TOP, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
451210284Sjmallett    if (console_block_addr < 0)
452210284Sjmallett        console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, DDR2_BASE + 1, DDR2_BASE + alloc_size + 128, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
453210284Sjmallett    if (console_block_addr < 0)
454210284Sjmallett        console_block_addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, 0, 0x7fffffff, 128, OCTEON_PCI_CONSOLE_BLOCK_NAME, CVMX_BOOTMEM_FLAG_END_ALLOC);
455210284Sjmallett    if (console_block_addr < 0)
456210284Sjmallett        return 0;
457210284Sjmallett
458210284Sjmallett    cons_desc_ptr = (void *)(uint32_t)console_block_addr;
459210284Sjmallett
460210284Sjmallett    memset(cons_desc_ptr, 0, alloc_size);  /* Clear entire alloc'ed memory */
461210284Sjmallett
462210284Sjmallett    cons_desc_ptr->lock = 1; /* initialize as locked until we are done */
463210284Sjmallett    CVMX_SYNCW;
464210284Sjmallett    cons_desc_ptr->num_consoles = num_consoles;
465210284Sjmallett    cons_desc_ptr->flags = 0;
466210284Sjmallett    cons_desc_ptr->major_version = OCTEON_PCI_CONSOLE_MAJOR_VERSION;
467210284Sjmallett    cons_desc_ptr->minor_version = OCTEON_PCI_CONSOLE_MINOR_VERSION;
468210284Sjmallett
469210284Sjmallett    int i;
470210284Sjmallett    uint64_t avail_addr = console_block_addr + sizeof(octeon_pci_console_desc_t) + num_consoles * sizeof(uint64_t);
471210284Sjmallett    for (i = 0; i < num_consoles;i++)
472210284Sjmallett    {
473210284Sjmallett        cons_desc_ptr->console_addr_array[i] = avail_addr;
474210284Sjmallett        cons_ptr = (void *)(uint32_t)cons_desc_ptr->console_addr_array[i];
475210284Sjmallett        avail_addr += sizeof(octeon_pci_console_t);
476210284Sjmallett        cons_ptr->input_base_addr = avail_addr;
477210284Sjmallett        avail_addr += buffer_size;
478210284Sjmallett        cons_ptr->output_base_addr = avail_addr;
479210284Sjmallett        avail_addr += buffer_size;
480210284Sjmallett        cons_ptr->buf_size = buffer_size;
481210284Sjmallett    }
482210284Sjmallett    CVMX_SYNCW;
483210284Sjmallett    cons_desc_ptr->lock = 0;
484210284Sjmallett
485210284Sjmallett    return console_block_addr;
486210284Sjmallett
487210284Sjmallett
488210284Sjmallett}
489210284Sjmallett#endif
490