1*4882a593Smuzhiyun /**********************************************************************
2*4882a593Smuzhiyun * Author: Cavium, Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Contact: support@cavium.com
5*4882a593Smuzhiyun * Please include "LiquidIO" in the subject.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (c) 2003-2016 Cavium, Inc.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This file is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun * it under the terms of the GNU General Public License, Version 2, as
11*4882a593Smuzhiyun * published by the Free Software Foundation.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This file is distributed in the hope that it will be useful, but
14*4882a593Smuzhiyun * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16*4882a593Smuzhiyun * NONINFRINGEMENT. See the GNU General Public License for more details.
17*4882a593Smuzhiyun ***********************************************************************/
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun * @file octeon_console.c
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun #include <linux/moduleparam.h>
22*4882a593Smuzhiyun #include <linux/pci.h>
23*4882a593Smuzhiyun #include <linux/netdevice.h>
24*4882a593Smuzhiyun #include <linux/crc32.h>
25*4882a593Smuzhiyun #include "liquidio_common.h"
26*4882a593Smuzhiyun #include "octeon_droq.h"
27*4882a593Smuzhiyun #include "octeon_iq.h"
28*4882a593Smuzhiyun #include "response_manager.h"
29*4882a593Smuzhiyun #include "octeon_device.h"
30*4882a593Smuzhiyun #include "liquidio_image.h"
31*4882a593Smuzhiyun #include "octeon_mem_ops.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun static void octeon_remote_lock(void);
34*4882a593Smuzhiyun static void octeon_remote_unlock(void);
35*4882a593Smuzhiyun static u64 cvmx_bootmem_phy_named_block_find(struct octeon_device *oct,
36*4882a593Smuzhiyun const char *name,
37*4882a593Smuzhiyun u32 flags);
38*4882a593Smuzhiyun static int octeon_console_read(struct octeon_device *oct, u32 console_num,
39*4882a593Smuzhiyun char *buffer, u32 buf_size);
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR 0x0006c008
42*4882a593Smuzhiyun #define BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR 0x0006c004
43*4882a593Smuzhiyun #define BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR 0x0006c000
44*4882a593Smuzhiyun #define BOOTLOADER_PCI_READ_DESC_ADDR 0x0006c100
45*4882a593Smuzhiyun #define BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN 248
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define OCTEON_PCI_IO_BUF_OWNER_OCTEON 0x00000001
48*4882a593Smuzhiyun #define OCTEON_PCI_IO_BUF_OWNER_HOST 0x00000002
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /** Can change without breaking ABI */
51*4882a593Smuzhiyun #define CVMX_BOOTMEM_NUM_NAMED_BLOCKS 64
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /** minimum alignment of bootmem alloced blocks */
54*4882a593Smuzhiyun #define CVMX_BOOTMEM_ALIGNMENT_SIZE (16ull)
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /** CVMX bootmem descriptor major version */
57*4882a593Smuzhiyun #define CVMX_BOOTMEM_DESC_MAJ_VER 3
58*4882a593Smuzhiyun /* CVMX bootmem descriptor minor version */
59*4882a593Smuzhiyun #define CVMX_BOOTMEM_DESC_MIN_VER 0
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* Current versions */
62*4882a593Smuzhiyun #define OCTEON_PCI_CONSOLE_MAJOR_VERSION 1
63*4882a593Smuzhiyun #define OCTEON_PCI_CONSOLE_MINOR_VERSION 0
64*4882a593Smuzhiyun #define OCTEON_PCI_CONSOLE_BLOCK_NAME "__pci_console"
65*4882a593Smuzhiyun #define OCTEON_CONSOLE_POLL_INTERVAL_MS 100 /* 10 times per second */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* First three members of cvmx_bootmem_desc are left in original
68*4882a593Smuzhiyun * positions for backwards compatibility.
69*4882a593Smuzhiyun * Assumes big endian target
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun struct cvmx_bootmem_desc {
72*4882a593Smuzhiyun /** spinlock to control access to list */
73*4882a593Smuzhiyun u32 lock;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /** flags for indicating various conditions */
76*4882a593Smuzhiyun u32 flags;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun u64 head_addr;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /** incremented changed when incompatible changes made */
81*4882a593Smuzhiyun u32 major_version;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /** incremented changed when compatible changes made,
84*4882a593Smuzhiyun * reset to zero when major incremented
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun u32 minor_version;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun u64 app_data_addr;
89*4882a593Smuzhiyun u64 app_data_size;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /** number of elements in named blocks array */
92*4882a593Smuzhiyun u32 nb_num_blocks;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /** length of name array in bootmem blocks */
95*4882a593Smuzhiyun u32 named_block_name_len;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /** address of named memory block descriptors */
98*4882a593Smuzhiyun u64 named_block_array_addr;
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* Structure that defines a single console.
102*4882a593Smuzhiyun *
103*4882a593Smuzhiyun * Note: when read_index == write_index, the buffer is empty.
104*4882a593Smuzhiyun * The actual usable size of each console is console_buf_size -1;
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun struct octeon_pci_console {
107*4882a593Smuzhiyun u64 input_base_addr;
108*4882a593Smuzhiyun u32 input_read_index;
109*4882a593Smuzhiyun u32 input_write_index;
110*4882a593Smuzhiyun u64 output_base_addr;
111*4882a593Smuzhiyun u32 output_read_index;
112*4882a593Smuzhiyun u32 output_write_index;
113*4882a593Smuzhiyun u32 lock;
114*4882a593Smuzhiyun u32 buf_size;
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* This is the main container structure that contains all the information
118*4882a593Smuzhiyun * about all PCI consoles. The address of this structure is passed to various
119*4882a593Smuzhiyun * routines that operation on PCI consoles.
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun struct octeon_pci_console_desc {
122*4882a593Smuzhiyun u32 major_version;
123*4882a593Smuzhiyun u32 minor_version;
124*4882a593Smuzhiyun u32 lock;
125*4882a593Smuzhiyun u32 flags;
126*4882a593Smuzhiyun u32 num_consoles;
127*4882a593Smuzhiyun u32 pad;
128*4882a593Smuzhiyun /* must be 64 bit aligned here... */
129*4882a593Smuzhiyun /* Array of addresses of octeon_pci_console structures */
130*4882a593Smuzhiyun u64 console_addr_array[];
131*4882a593Smuzhiyun /* Implicit storage for console_addr_array */
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * This function is the implementation of the get macros defined
136*4882a593Smuzhiyun * for individual structure members. The argument are generated
137*4882a593Smuzhiyun * by the macros inorder to read only the needed memory.
138*4882a593Smuzhiyun *
139*4882a593Smuzhiyun * @param oct Pointer to current octeon device
140*4882a593Smuzhiyun * @param base 64bit physical address of the complete structure
141*4882a593Smuzhiyun * @param offset Offset from the beginning of the structure to the member being
142*4882a593Smuzhiyun * accessed.
143*4882a593Smuzhiyun * @param size Size of the structure member.
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * @return Value of the structure member promoted into a u64.
146*4882a593Smuzhiyun */
__cvmx_bootmem_desc_get(struct octeon_device * oct,u64 base,u32 offset,u32 size)147*4882a593Smuzhiyun static inline u64 __cvmx_bootmem_desc_get(struct octeon_device *oct,
148*4882a593Smuzhiyun u64 base,
149*4882a593Smuzhiyun u32 offset,
150*4882a593Smuzhiyun u32 size)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun base = (1ull << 63) | (base + offset);
153*4882a593Smuzhiyun switch (size) {
154*4882a593Smuzhiyun case 4:
155*4882a593Smuzhiyun return octeon_read_device_mem32(oct, base);
156*4882a593Smuzhiyun case 8:
157*4882a593Smuzhiyun return octeon_read_device_mem64(oct, base);
158*4882a593Smuzhiyun default:
159*4882a593Smuzhiyun return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun * This function retrieves the string name of a named block. It is
165*4882a593Smuzhiyun * more complicated than a simple memcpy() since the named block
166*4882a593Smuzhiyun * descriptor may not be directly accessible.
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * @param addr Physical address of the named block descriptor
169*4882a593Smuzhiyun * @param str String to receive the named block string name
170*4882a593Smuzhiyun * @param len Length of the string buffer, which must match the length
171*4882a593Smuzhiyun * stored in the bootmem descriptor.
172*4882a593Smuzhiyun */
CVMX_BOOTMEM_NAMED_GET_NAME(struct octeon_device * oct,u64 addr,char * str,u32 len)173*4882a593Smuzhiyun static void CVMX_BOOTMEM_NAMED_GET_NAME(struct octeon_device *oct,
174*4882a593Smuzhiyun u64 addr,
175*4882a593Smuzhiyun char *str,
176*4882a593Smuzhiyun u32 len)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun addr += offsetof(struct cvmx_bootmem_named_block_desc, name);
179*4882a593Smuzhiyun octeon_pci_read_core_mem(oct, addr, (u8 *)str, len);
180*4882a593Smuzhiyun str[len] = 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* See header file for descriptions of functions */
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /*
186*4882a593Smuzhiyun * Check the version information on the bootmem descriptor
187*4882a593Smuzhiyun *
188*4882a593Smuzhiyun * @param exact_match
189*4882a593Smuzhiyun * Exact major version to check against. A zero means
190*4882a593Smuzhiyun * check that the version supports named blocks.
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun * @return Zero if the version is correct. Negative if the version is
193*4882a593Smuzhiyun * incorrect. Failures also cause a message to be displayed.
194*4882a593Smuzhiyun */
__cvmx_bootmem_check_version(struct octeon_device * oct,u32 exact_match)195*4882a593Smuzhiyun static int __cvmx_bootmem_check_version(struct octeon_device *oct,
196*4882a593Smuzhiyun u32 exact_match)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun u32 major_version;
199*4882a593Smuzhiyun u32 minor_version;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun if (!oct->bootmem_desc_addr)
202*4882a593Smuzhiyun oct->bootmem_desc_addr =
203*4882a593Smuzhiyun octeon_read_device_mem64(oct,
204*4882a593Smuzhiyun BOOTLOADER_PCI_READ_DESC_ADDR);
205*4882a593Smuzhiyun major_version = (u32)__cvmx_bootmem_desc_get(
206*4882a593Smuzhiyun oct, oct->bootmem_desc_addr,
207*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_desc, major_version),
208*4882a593Smuzhiyun sizeof_field(struct cvmx_bootmem_desc, major_version));
209*4882a593Smuzhiyun minor_version = (u32)__cvmx_bootmem_desc_get(
210*4882a593Smuzhiyun oct, oct->bootmem_desc_addr,
211*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_desc, minor_version),
212*4882a593Smuzhiyun sizeof_field(struct cvmx_bootmem_desc, minor_version));
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun dev_dbg(&oct->pci_dev->dev, "%s: major_version=%d\n", __func__,
215*4882a593Smuzhiyun major_version);
216*4882a593Smuzhiyun if ((major_version > 3) ||
217*4882a593Smuzhiyun (exact_match && major_version != exact_match)) {
218*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "bootmem ver mismatch %d.%d addr:0x%llx\n",
219*4882a593Smuzhiyun major_version, minor_version,
220*4882a593Smuzhiyun (long long)oct->bootmem_desc_addr);
221*4882a593Smuzhiyun return -1;
222*4882a593Smuzhiyun } else {
223*4882a593Smuzhiyun return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun static const struct cvmx_bootmem_named_block_desc
__cvmx_bootmem_find_named_block_flags(struct octeon_device * oct,const char * name,u32 flags)228*4882a593Smuzhiyun *__cvmx_bootmem_find_named_block_flags(struct octeon_device *oct,
229*4882a593Smuzhiyun const char *name, u32 flags)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun struct cvmx_bootmem_named_block_desc *desc =
232*4882a593Smuzhiyun &oct->bootmem_named_block_desc;
233*4882a593Smuzhiyun u64 named_addr = cvmx_bootmem_phy_named_block_find(oct, name, flags);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun if (named_addr) {
236*4882a593Smuzhiyun desc->base_addr = __cvmx_bootmem_desc_get(
237*4882a593Smuzhiyun oct, named_addr,
238*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_named_block_desc,
239*4882a593Smuzhiyun base_addr),
240*4882a593Smuzhiyun sizeof_field(
241*4882a593Smuzhiyun struct cvmx_bootmem_named_block_desc,
242*4882a593Smuzhiyun base_addr));
243*4882a593Smuzhiyun desc->size = __cvmx_bootmem_desc_get(oct, named_addr,
244*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_named_block_desc,
245*4882a593Smuzhiyun size),
246*4882a593Smuzhiyun sizeof_field(
247*4882a593Smuzhiyun struct cvmx_bootmem_named_block_desc,
248*4882a593Smuzhiyun size));
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun strncpy(desc->name, name, sizeof(desc->name));
251*4882a593Smuzhiyun desc->name[sizeof(desc->name) - 1] = 0;
252*4882a593Smuzhiyun return &oct->bootmem_named_block_desc;
253*4882a593Smuzhiyun } else {
254*4882a593Smuzhiyun return NULL;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
cvmx_bootmem_phy_named_block_find(struct octeon_device * oct,const char * name,u32 flags)258*4882a593Smuzhiyun static u64 cvmx_bootmem_phy_named_block_find(struct octeon_device *oct,
259*4882a593Smuzhiyun const char *name,
260*4882a593Smuzhiyun u32 flags)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun u64 result = 0;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (!__cvmx_bootmem_check_version(oct, 3)) {
265*4882a593Smuzhiyun u32 i;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun u64 named_block_array_addr = __cvmx_bootmem_desc_get(
268*4882a593Smuzhiyun oct, oct->bootmem_desc_addr,
269*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_desc,
270*4882a593Smuzhiyun named_block_array_addr),
271*4882a593Smuzhiyun sizeof_field(struct cvmx_bootmem_desc,
272*4882a593Smuzhiyun named_block_array_addr));
273*4882a593Smuzhiyun u32 num_blocks = (u32)__cvmx_bootmem_desc_get(
274*4882a593Smuzhiyun oct, oct->bootmem_desc_addr,
275*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_desc,
276*4882a593Smuzhiyun nb_num_blocks),
277*4882a593Smuzhiyun sizeof_field(struct cvmx_bootmem_desc,
278*4882a593Smuzhiyun nb_num_blocks));
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun u32 name_length = (u32)__cvmx_bootmem_desc_get(
281*4882a593Smuzhiyun oct, oct->bootmem_desc_addr,
282*4882a593Smuzhiyun offsetof(struct cvmx_bootmem_desc,
283*4882a593Smuzhiyun named_block_name_len),
284*4882a593Smuzhiyun sizeof_field(struct cvmx_bootmem_desc,
285*4882a593Smuzhiyun named_block_name_len));
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun u64 named_addr = named_block_array_addr;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun for (i = 0; i < num_blocks; i++) {
290*4882a593Smuzhiyun u64 named_size = __cvmx_bootmem_desc_get(
291*4882a593Smuzhiyun oct, named_addr,
292*4882a593Smuzhiyun offsetof(
293*4882a593Smuzhiyun struct cvmx_bootmem_named_block_desc,
294*4882a593Smuzhiyun size),
295*4882a593Smuzhiyun sizeof_field(
296*4882a593Smuzhiyun struct cvmx_bootmem_named_block_desc,
297*4882a593Smuzhiyun size));
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (name && named_size) {
300*4882a593Smuzhiyun char *name_tmp =
301*4882a593Smuzhiyun kmalloc(name_length + 1, GFP_KERNEL);
302*4882a593Smuzhiyun if (!name_tmp)
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun CVMX_BOOTMEM_NAMED_GET_NAME(oct, named_addr,
306*4882a593Smuzhiyun name_tmp,
307*4882a593Smuzhiyun name_length);
308*4882a593Smuzhiyun if (!strncmp(name, name_tmp, name_length)) {
309*4882a593Smuzhiyun result = named_addr;
310*4882a593Smuzhiyun kfree(name_tmp);
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun kfree(name_tmp);
314*4882a593Smuzhiyun } else if (!name && !named_size) {
315*4882a593Smuzhiyun result = named_addr;
316*4882a593Smuzhiyun break;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun named_addr +=
320*4882a593Smuzhiyun sizeof(struct cvmx_bootmem_named_block_desc);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun return result;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /*
327*4882a593Smuzhiyun * Find a named block on the remote Octeon
328*4882a593Smuzhiyun *
329*4882a593Smuzhiyun * @param name Name of block to find
330*4882a593Smuzhiyun * @param base_addr Address the block is at (OUTPUT)
331*4882a593Smuzhiyun * @param size The size of the block (OUTPUT)
332*4882a593Smuzhiyun *
333*4882a593Smuzhiyun * @return Zero on success, One on failure.
334*4882a593Smuzhiyun */
octeon_named_block_find(struct octeon_device * oct,const char * name,u64 * base_addr,u64 * size)335*4882a593Smuzhiyun static int octeon_named_block_find(struct octeon_device *oct, const char *name,
336*4882a593Smuzhiyun u64 *base_addr, u64 *size)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun const struct cvmx_bootmem_named_block_desc *named_block;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun octeon_remote_lock();
341*4882a593Smuzhiyun named_block = __cvmx_bootmem_find_named_block_flags(oct, name, 0);
342*4882a593Smuzhiyun octeon_remote_unlock();
343*4882a593Smuzhiyun if (named_block) {
344*4882a593Smuzhiyun *base_addr = named_block->base_addr;
345*4882a593Smuzhiyun *size = named_block->size;
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun return 1;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
octeon_remote_lock(void)351*4882a593Smuzhiyun static void octeon_remote_lock(void)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun /* fill this in if any sharing is needed */
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
octeon_remote_unlock(void)356*4882a593Smuzhiyun static void octeon_remote_unlock(void)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun /* fill this in if any sharing is needed */
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
octeon_console_send_cmd(struct octeon_device * oct,char * cmd_str,u32 wait_hundredths)361*4882a593Smuzhiyun int octeon_console_send_cmd(struct octeon_device *oct, char *cmd_str,
362*4882a593Smuzhiyun u32 wait_hundredths)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun u32 len = (u32)strlen(cmd_str);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun dev_dbg(&oct->pci_dev->dev, "sending \"%s\" to bootloader\n", cmd_str);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (len > BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1) {
369*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Command string too long, max length is: %d\n",
370*4882a593Smuzhiyun BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1);
371*4882a593Smuzhiyun return -1;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (octeon_wait_for_bootloader(oct, wait_hundredths) != 0) {
375*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Bootloader not ready for command.\n");
376*4882a593Smuzhiyun return -1;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* Write command to bootloader */
380*4882a593Smuzhiyun octeon_remote_lock();
381*4882a593Smuzhiyun octeon_pci_write_core_mem(oct, BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR,
382*4882a593Smuzhiyun (u8 *)cmd_str, len);
383*4882a593Smuzhiyun octeon_write_device_mem32(oct, BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR,
384*4882a593Smuzhiyun len);
385*4882a593Smuzhiyun octeon_write_device_mem32(oct, BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR,
386*4882a593Smuzhiyun OCTEON_PCI_IO_BUF_OWNER_OCTEON);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* Bootloader should accept command very quickly
389*4882a593Smuzhiyun * if it really was ready
390*4882a593Smuzhiyun */
391*4882a593Smuzhiyun if (octeon_wait_for_bootloader(oct, 200) != 0) {
392*4882a593Smuzhiyun octeon_remote_unlock();
393*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Bootloader did not accept command.\n");
394*4882a593Smuzhiyun return -1;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun octeon_remote_unlock();
397*4882a593Smuzhiyun return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
octeon_wait_for_bootloader(struct octeon_device * oct,u32 wait_time_hundredths)400*4882a593Smuzhiyun int octeon_wait_for_bootloader(struct octeon_device *oct,
401*4882a593Smuzhiyun u32 wait_time_hundredths)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun dev_dbg(&oct->pci_dev->dev, "waiting %d0 ms for bootloader\n",
404*4882a593Smuzhiyun wait_time_hundredths);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if (octeon_mem_access_ok(oct))
407*4882a593Smuzhiyun return -1;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun while (wait_time_hundredths > 0 &&
410*4882a593Smuzhiyun octeon_read_device_mem32(oct,
411*4882a593Smuzhiyun BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR)
412*4882a593Smuzhiyun != OCTEON_PCI_IO_BUF_OWNER_HOST) {
413*4882a593Smuzhiyun if (--wait_time_hundredths <= 0)
414*4882a593Smuzhiyun return -1;
415*4882a593Smuzhiyun schedule_timeout_uninterruptible(HZ / 100);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
octeon_console_handle_result(struct octeon_device * oct,size_t console_num)420*4882a593Smuzhiyun static void octeon_console_handle_result(struct octeon_device *oct,
421*4882a593Smuzhiyun size_t console_num)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun struct octeon_console *console;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun console = &oct->console[console_num];
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun console->waiting = 0;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun static char console_buffer[OCTEON_CONSOLE_MAX_READ_BYTES];
431*4882a593Smuzhiyun
output_console_line(struct octeon_device * oct,struct octeon_console * console,size_t console_num,char * console_buffer,s32 bytes_read)432*4882a593Smuzhiyun static void output_console_line(struct octeon_device *oct,
433*4882a593Smuzhiyun struct octeon_console *console,
434*4882a593Smuzhiyun size_t console_num,
435*4882a593Smuzhiyun char *console_buffer,
436*4882a593Smuzhiyun s32 bytes_read)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun char *line;
439*4882a593Smuzhiyun s32 i;
440*4882a593Smuzhiyun size_t len;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun line = console_buffer;
443*4882a593Smuzhiyun for (i = 0; i < bytes_read; i++) {
444*4882a593Smuzhiyun /* Output a line at a time, prefixed */
445*4882a593Smuzhiyun if (console_buffer[i] == '\n') {
446*4882a593Smuzhiyun console_buffer[i] = '\0';
447*4882a593Smuzhiyun /* We need to output 'line', prefaced by 'leftover'.
448*4882a593Smuzhiyun * However, it is possible we're being called to
449*4882a593Smuzhiyun * output 'leftover' by itself (in the case of nothing
450*4882a593Smuzhiyun * having been read from the console).
451*4882a593Smuzhiyun *
452*4882a593Smuzhiyun * To avoid duplication, check for this condition.
453*4882a593Smuzhiyun */
454*4882a593Smuzhiyun if (console->leftover[0] &&
455*4882a593Smuzhiyun (line != console->leftover)) {
456*4882a593Smuzhiyun if (console->print)
457*4882a593Smuzhiyun (*console->print)(oct, (u32)console_num,
458*4882a593Smuzhiyun console->leftover,
459*4882a593Smuzhiyun line);
460*4882a593Smuzhiyun console->leftover[0] = '\0';
461*4882a593Smuzhiyun } else {
462*4882a593Smuzhiyun if (console->print)
463*4882a593Smuzhiyun (*console->print)(oct, (u32)console_num,
464*4882a593Smuzhiyun line, NULL);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun line = &console_buffer[i + 1];
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun /* Save off any leftovers */
471*4882a593Smuzhiyun if (line != &console_buffer[bytes_read]) {
472*4882a593Smuzhiyun console_buffer[bytes_read] = '\0';
473*4882a593Smuzhiyun len = strlen(console->leftover);
474*4882a593Smuzhiyun strncpy(&console->leftover[len], line,
475*4882a593Smuzhiyun sizeof(console->leftover) - len);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
check_console(struct work_struct * work)479*4882a593Smuzhiyun static void check_console(struct work_struct *work)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun s32 bytes_read, tries, total_read;
482*4882a593Smuzhiyun size_t len;
483*4882a593Smuzhiyun struct octeon_console *console;
484*4882a593Smuzhiyun struct cavium_wk *wk = (struct cavium_wk *)work;
485*4882a593Smuzhiyun struct octeon_device *oct = (struct octeon_device *)wk->ctxptr;
486*4882a593Smuzhiyun u32 console_num = (u32)wk->ctxul;
487*4882a593Smuzhiyun u32 delay;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun console = &oct->console[console_num];
490*4882a593Smuzhiyun tries = 0;
491*4882a593Smuzhiyun total_read = 0;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun do {
494*4882a593Smuzhiyun /* Take console output regardless of whether it will
495*4882a593Smuzhiyun * be logged
496*4882a593Smuzhiyun */
497*4882a593Smuzhiyun bytes_read =
498*4882a593Smuzhiyun octeon_console_read(oct, console_num, console_buffer,
499*4882a593Smuzhiyun sizeof(console_buffer) - 1);
500*4882a593Smuzhiyun if (bytes_read > 0) {
501*4882a593Smuzhiyun total_read += bytes_read;
502*4882a593Smuzhiyun if (console->waiting)
503*4882a593Smuzhiyun octeon_console_handle_result(oct, console_num);
504*4882a593Smuzhiyun if (console->print) {
505*4882a593Smuzhiyun output_console_line(oct, console, console_num,
506*4882a593Smuzhiyun console_buffer, bytes_read);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun } else if (bytes_read < 0) {
509*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Error reading console %u, ret=%d\n",
510*4882a593Smuzhiyun console_num, bytes_read);
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun tries++;
514*4882a593Smuzhiyun } while ((bytes_read > 0) && (tries < 16));
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* If nothing is read after polling the console,
517*4882a593Smuzhiyun * output any leftovers if any
518*4882a593Smuzhiyun */
519*4882a593Smuzhiyun if (console->print && (total_read == 0) &&
520*4882a593Smuzhiyun (console->leftover[0])) {
521*4882a593Smuzhiyun /* append '\n' as terminator for 'output_console_line' */
522*4882a593Smuzhiyun len = strlen(console->leftover);
523*4882a593Smuzhiyun console->leftover[len] = '\n';
524*4882a593Smuzhiyun output_console_line(oct, console, console_num,
525*4882a593Smuzhiyun console->leftover, (s32)(len + 1));
526*4882a593Smuzhiyun console->leftover[0] = '\0';
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun delay = OCTEON_CONSOLE_POLL_INTERVAL_MS;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun schedule_delayed_work(&wk->work, msecs_to_jiffies(delay));
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
octeon_init_consoles(struct octeon_device * oct)534*4882a593Smuzhiyun int octeon_init_consoles(struct octeon_device *oct)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun int ret = 0;
537*4882a593Smuzhiyun u64 addr, size;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun ret = octeon_mem_access_ok(oct);
540*4882a593Smuzhiyun if (ret) {
541*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Memory access not okay'\n");
542*4882a593Smuzhiyun return ret;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun ret = octeon_named_block_find(oct, OCTEON_PCI_CONSOLE_BLOCK_NAME, &addr,
546*4882a593Smuzhiyun &size);
547*4882a593Smuzhiyun if (ret) {
548*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Could not find console '%s'\n",
549*4882a593Smuzhiyun OCTEON_PCI_CONSOLE_BLOCK_NAME);
550*4882a593Smuzhiyun return ret;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* Dedicate one of Octeon's BAR1 index registers to create a static
554*4882a593Smuzhiyun * mapping to a region of Octeon DRAM that contains the PCI console
555*4882a593Smuzhiyun * named block.
556*4882a593Smuzhiyun */
557*4882a593Smuzhiyun oct->console_nb_info.bar1_index = BAR1_INDEX_STATIC_MAP;
558*4882a593Smuzhiyun oct->fn_list.bar1_idx_setup(oct, addr, oct->console_nb_info.bar1_index,
559*4882a593Smuzhiyun true);
560*4882a593Smuzhiyun oct->console_nb_info.dram_region_base = addr
561*4882a593Smuzhiyun & ~(OCTEON_BAR1_ENTRY_SIZE - 1ULL);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun /* num_consoles > 0, is an indication that the consoles
564*4882a593Smuzhiyun * are accessible
565*4882a593Smuzhiyun */
566*4882a593Smuzhiyun oct->num_consoles = octeon_read_device_mem32(oct,
567*4882a593Smuzhiyun addr + offsetof(struct octeon_pci_console_desc,
568*4882a593Smuzhiyun num_consoles));
569*4882a593Smuzhiyun oct->console_desc_addr = addr;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun dev_dbg(&oct->pci_dev->dev, "Initialized consoles. %d available\n",
572*4882a593Smuzhiyun oct->num_consoles);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun return ret;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
octeon_get_uboot_version(struct octeon_device * oct)577*4882a593Smuzhiyun static void octeon_get_uboot_version(struct octeon_device *oct)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun s32 bytes_read, tries, total_read;
580*4882a593Smuzhiyun struct octeon_console *console;
581*4882a593Smuzhiyun u32 console_num = 0;
582*4882a593Smuzhiyun char *uboot_ver;
583*4882a593Smuzhiyun char *buf;
584*4882a593Smuzhiyun char *p;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun #define OCTEON_UBOOT_VER_BUF_SIZE 512
587*4882a593Smuzhiyun buf = kmalloc(OCTEON_UBOOT_VER_BUF_SIZE, GFP_KERNEL);
588*4882a593Smuzhiyun if (!buf)
589*4882a593Smuzhiyun return;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun if (octeon_console_send_cmd(oct, "setenv stdout pci\n", 50)) {
592*4882a593Smuzhiyun kfree(buf);
593*4882a593Smuzhiyun return;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun if (octeon_console_send_cmd(oct, "version\n", 1)) {
597*4882a593Smuzhiyun kfree(buf);
598*4882a593Smuzhiyun return;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun console = &oct->console[console_num];
602*4882a593Smuzhiyun tries = 0;
603*4882a593Smuzhiyun total_read = 0;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun do {
606*4882a593Smuzhiyun /* Take console output regardless of whether it will
607*4882a593Smuzhiyun * be logged
608*4882a593Smuzhiyun */
609*4882a593Smuzhiyun bytes_read =
610*4882a593Smuzhiyun octeon_console_read(oct,
611*4882a593Smuzhiyun console_num, buf + total_read,
612*4882a593Smuzhiyun OCTEON_UBOOT_VER_BUF_SIZE - 1 -
613*4882a593Smuzhiyun total_read);
614*4882a593Smuzhiyun if (bytes_read > 0) {
615*4882a593Smuzhiyun buf[bytes_read] = '\0';
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun total_read += bytes_read;
618*4882a593Smuzhiyun if (console->waiting)
619*4882a593Smuzhiyun octeon_console_handle_result(oct, console_num);
620*4882a593Smuzhiyun } else if (bytes_read < 0) {
621*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Error reading console %u, ret=%d\n",
622*4882a593Smuzhiyun console_num, bytes_read);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun tries++;
626*4882a593Smuzhiyun } while ((bytes_read > 0) && (tries < 16));
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun /* If nothing is read after polling the console,
629*4882a593Smuzhiyun * output any leftovers if any
630*4882a593Smuzhiyun */
631*4882a593Smuzhiyun if ((total_read == 0) && (console->leftover[0])) {
632*4882a593Smuzhiyun dev_dbg(&oct->pci_dev->dev, "%u: %s\n",
633*4882a593Smuzhiyun console_num, console->leftover);
634*4882a593Smuzhiyun console->leftover[0] = '\0';
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun buf[OCTEON_UBOOT_VER_BUF_SIZE - 1] = '\0';
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun uboot_ver = strstr(buf, "U-Boot");
640*4882a593Smuzhiyun if (uboot_ver) {
641*4882a593Smuzhiyun p = strstr(uboot_ver, "mips");
642*4882a593Smuzhiyun if (p) {
643*4882a593Smuzhiyun p--;
644*4882a593Smuzhiyun *p = '\0';
645*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "%s\n", uboot_ver);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun kfree(buf);
650*4882a593Smuzhiyun octeon_console_send_cmd(oct, "setenv stdout serial\n", 50);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
octeon_add_console(struct octeon_device * oct,u32 console_num,char * dbg_enb)653*4882a593Smuzhiyun int octeon_add_console(struct octeon_device *oct, u32 console_num,
654*4882a593Smuzhiyun char *dbg_enb)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun int ret = 0;
657*4882a593Smuzhiyun u32 delay;
658*4882a593Smuzhiyun u64 coreaddr;
659*4882a593Smuzhiyun struct delayed_work *work;
660*4882a593Smuzhiyun struct octeon_console *console;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun if (console_num >= oct->num_consoles) {
663*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev,
664*4882a593Smuzhiyun "trying to read from console number %d when only 0 to %d exist\n",
665*4882a593Smuzhiyun console_num, oct->num_consoles);
666*4882a593Smuzhiyun } else {
667*4882a593Smuzhiyun console = &oct->console[console_num];
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun console->waiting = 0;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun coreaddr = oct->console_desc_addr + console_num * 8 +
672*4882a593Smuzhiyun offsetof(struct octeon_pci_console_desc,
673*4882a593Smuzhiyun console_addr_array);
674*4882a593Smuzhiyun console->addr = octeon_read_device_mem64(oct, coreaddr);
675*4882a593Smuzhiyun coreaddr = console->addr + offsetof(struct octeon_pci_console,
676*4882a593Smuzhiyun buf_size);
677*4882a593Smuzhiyun console->buffer_size = octeon_read_device_mem32(oct, coreaddr);
678*4882a593Smuzhiyun coreaddr = console->addr + offsetof(struct octeon_pci_console,
679*4882a593Smuzhiyun input_base_addr);
680*4882a593Smuzhiyun console->input_base_addr =
681*4882a593Smuzhiyun octeon_read_device_mem64(oct, coreaddr);
682*4882a593Smuzhiyun coreaddr = console->addr + offsetof(struct octeon_pci_console,
683*4882a593Smuzhiyun output_base_addr);
684*4882a593Smuzhiyun console->output_base_addr =
685*4882a593Smuzhiyun octeon_read_device_mem64(oct, coreaddr);
686*4882a593Smuzhiyun console->leftover[0] = '\0';
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun work = &oct->console_poll_work[console_num].work;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun octeon_get_uboot_version(oct);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun INIT_DELAYED_WORK(work, check_console);
693*4882a593Smuzhiyun oct->console_poll_work[console_num].ctxptr = (void *)oct;
694*4882a593Smuzhiyun oct->console_poll_work[console_num].ctxul = console_num;
695*4882a593Smuzhiyun delay = OCTEON_CONSOLE_POLL_INTERVAL_MS;
696*4882a593Smuzhiyun schedule_delayed_work(work, msecs_to_jiffies(delay));
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /* an empty string means use default debug console enablement */
699*4882a593Smuzhiyun if (dbg_enb && !dbg_enb[0])
700*4882a593Smuzhiyun dbg_enb = "setenv pci_console_active 1";
701*4882a593Smuzhiyun if (dbg_enb)
702*4882a593Smuzhiyun ret = octeon_console_send_cmd(oct, dbg_enb, 2000);
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun console->active = 1;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun return ret;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun /*
711*4882a593Smuzhiyun * Removes all consoles
712*4882a593Smuzhiyun *
713*4882a593Smuzhiyun * @param oct octeon device
714*4882a593Smuzhiyun */
octeon_remove_consoles(struct octeon_device * oct)715*4882a593Smuzhiyun void octeon_remove_consoles(struct octeon_device *oct)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun u32 i;
718*4882a593Smuzhiyun struct octeon_console *console;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun for (i = 0; i < oct->num_consoles; i++) {
721*4882a593Smuzhiyun console = &oct->console[i];
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (!console->active)
724*4882a593Smuzhiyun continue;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun cancel_delayed_work_sync(&oct->console_poll_work[i].
727*4882a593Smuzhiyun work);
728*4882a593Smuzhiyun console->addr = 0;
729*4882a593Smuzhiyun console->buffer_size = 0;
730*4882a593Smuzhiyun console->input_base_addr = 0;
731*4882a593Smuzhiyun console->output_base_addr = 0;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun oct->num_consoles = 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
octeon_console_free_bytes(u32 buffer_size,u32 wr_idx,u32 rd_idx)737*4882a593Smuzhiyun static inline int octeon_console_free_bytes(u32 buffer_size,
738*4882a593Smuzhiyun u32 wr_idx,
739*4882a593Smuzhiyun u32 rd_idx)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun if (rd_idx >= buffer_size || wr_idx >= buffer_size)
742*4882a593Smuzhiyun return -1;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun return ((buffer_size - 1) - (wr_idx - rd_idx)) % buffer_size;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
octeon_console_avail_bytes(u32 buffer_size,u32 wr_idx,u32 rd_idx)747*4882a593Smuzhiyun static inline int octeon_console_avail_bytes(u32 buffer_size,
748*4882a593Smuzhiyun u32 wr_idx,
749*4882a593Smuzhiyun u32 rd_idx)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun if (rd_idx >= buffer_size || wr_idx >= buffer_size)
752*4882a593Smuzhiyun return -1;
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun return buffer_size - 1 -
755*4882a593Smuzhiyun octeon_console_free_bytes(buffer_size, wr_idx, rd_idx);
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
octeon_console_read(struct octeon_device * oct,u32 console_num,char * buffer,u32 buf_size)758*4882a593Smuzhiyun static int octeon_console_read(struct octeon_device *oct, u32 console_num,
759*4882a593Smuzhiyun char *buffer, u32 buf_size)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun int bytes_to_read;
762*4882a593Smuzhiyun u32 rd_idx, wr_idx;
763*4882a593Smuzhiyun struct octeon_console *console;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (console_num >= oct->num_consoles) {
766*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Attempted to read from disabled console %d\n",
767*4882a593Smuzhiyun console_num);
768*4882a593Smuzhiyun return 0;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun console = &oct->console[console_num];
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun /* Check to see if any data is available.
774*4882a593Smuzhiyun * Maybe optimize this with 64-bit read.
775*4882a593Smuzhiyun */
776*4882a593Smuzhiyun rd_idx = octeon_read_device_mem32(oct, console->addr +
777*4882a593Smuzhiyun offsetof(struct octeon_pci_console, output_read_index));
778*4882a593Smuzhiyun wr_idx = octeon_read_device_mem32(oct, console->addr +
779*4882a593Smuzhiyun offsetof(struct octeon_pci_console, output_write_index));
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun bytes_to_read = octeon_console_avail_bytes(console->buffer_size,
782*4882a593Smuzhiyun wr_idx, rd_idx);
783*4882a593Smuzhiyun if (bytes_to_read <= 0)
784*4882a593Smuzhiyun return bytes_to_read;
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun bytes_to_read = min_t(s32, bytes_to_read, buf_size);
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun /* Check to see if what we want to read is not contiguous, and limit
789*4882a593Smuzhiyun * ourselves to the contiguous block
790*4882a593Smuzhiyun */
791*4882a593Smuzhiyun if (rd_idx + bytes_to_read >= console->buffer_size)
792*4882a593Smuzhiyun bytes_to_read = console->buffer_size - rd_idx;
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun octeon_pci_read_core_mem(oct, console->output_base_addr + rd_idx,
795*4882a593Smuzhiyun (u8 *)buffer, bytes_to_read);
796*4882a593Smuzhiyun octeon_write_device_mem32(oct, console->addr +
797*4882a593Smuzhiyun offsetof(struct octeon_pci_console,
798*4882a593Smuzhiyun output_read_index),
799*4882a593Smuzhiyun (rd_idx + bytes_to_read) %
800*4882a593Smuzhiyun console->buffer_size);
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun return bytes_to_read;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun #define FBUF_SIZE (4 * 1024 * 1024)
806*4882a593Smuzhiyun #define MAX_BOOTTIME_SIZE 80
807*4882a593Smuzhiyun
octeon_download_firmware(struct octeon_device * oct,const u8 * data,size_t size)808*4882a593Smuzhiyun int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
809*4882a593Smuzhiyun size_t size)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun struct octeon_firmware_file_header *h;
812*4882a593Smuzhiyun char boottime[MAX_BOOTTIME_SIZE];
813*4882a593Smuzhiyun struct timespec64 ts;
814*4882a593Smuzhiyun u32 crc32_result;
815*4882a593Smuzhiyun u64 load_addr;
816*4882a593Smuzhiyun u32 image_len;
817*4882a593Smuzhiyun int ret = 0;
818*4882a593Smuzhiyun u32 i, rem;
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun if (size < sizeof(struct octeon_firmware_file_header)) {
821*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
822*4882a593Smuzhiyun (u32)size,
823*4882a593Smuzhiyun (u32)sizeof(struct octeon_firmware_file_header));
824*4882a593Smuzhiyun return -EINVAL;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun h = (struct octeon_firmware_file_header *)data;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun if (be32_to_cpu(h->magic) != LIO_NIC_MAGIC) {
830*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Unrecognized firmware file.\n");
831*4882a593Smuzhiyun return -EINVAL;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun crc32_result = crc32((unsigned int)~0, data,
835*4882a593Smuzhiyun sizeof(struct octeon_firmware_file_header) -
836*4882a593Smuzhiyun sizeof(u32)) ^ ~0U;
837*4882a593Smuzhiyun if (crc32_result != be32_to_cpu(h->crc32)) {
838*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Firmware CRC mismatch (0x%08x != 0x%08x).\n",
839*4882a593Smuzhiyun crc32_result, be32_to_cpu(h->crc32));
840*4882a593Smuzhiyun return -EINVAL;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun if (memcmp(LIQUIDIO_BASE_VERSION, h->version,
844*4882a593Smuzhiyun strlen(LIQUIDIO_BASE_VERSION))) {
845*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s.x, got %s.\n",
846*4882a593Smuzhiyun LIQUIDIO_BASE_VERSION,
847*4882a593Smuzhiyun h->version);
848*4882a593Smuzhiyun return -EINVAL;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun if (be32_to_cpu(h->num_images) > LIO_MAX_IMAGES) {
852*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Too many images in firmware file (%d).\n",
853*4882a593Smuzhiyun be32_to_cpu(h->num_images));
854*4882a593Smuzhiyun return -EINVAL;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "Firmware version: %s\n", h->version);
858*4882a593Smuzhiyun snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s",
859*4882a593Smuzhiyun h->version);
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun data += sizeof(struct octeon_firmware_file_header);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "%s: Loading %d images\n", __func__,
864*4882a593Smuzhiyun be32_to_cpu(h->num_images));
865*4882a593Smuzhiyun /* load all images */
866*4882a593Smuzhiyun for (i = 0; i < be32_to_cpu(h->num_images); i++) {
867*4882a593Smuzhiyun load_addr = be64_to_cpu(h->desc[i].addr);
868*4882a593Smuzhiyun image_len = be32_to_cpu(h->desc[i].len);
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "Loading firmware %d at %llx\n",
871*4882a593Smuzhiyun image_len, load_addr);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun /* Write in 4MB chunks*/
874*4882a593Smuzhiyun rem = image_len;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun while (rem) {
877*4882a593Smuzhiyun if (rem < FBUF_SIZE)
878*4882a593Smuzhiyun size = rem;
879*4882a593Smuzhiyun else
880*4882a593Smuzhiyun size = FBUF_SIZE;
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun /* download the image */
883*4882a593Smuzhiyun octeon_pci_write_core_mem(oct, load_addr, data, (u32)size);
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun data += size;
886*4882a593Smuzhiyun rem -= (u32)size;
887*4882a593Smuzhiyun load_addr += size;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun /* Pass date and time information to NIC at the time of loading
892*4882a593Smuzhiyun * firmware and periodically update the host time to NIC firmware.
893*4882a593Smuzhiyun * This is to make NIC firmware use the same time reference as Host,
894*4882a593Smuzhiyun * so that it is easy to correlate logs from firmware and host for
895*4882a593Smuzhiyun * debugging.
896*4882a593Smuzhiyun *
897*4882a593Smuzhiyun * Octeon always uses UTC time. so timezone information is not sent.
898*4882a593Smuzhiyun */
899*4882a593Smuzhiyun ktime_get_real_ts64(&ts);
900*4882a593Smuzhiyun ret = snprintf(boottime, MAX_BOOTTIME_SIZE,
901*4882a593Smuzhiyun " time_sec=%lld time_nsec=%ld",
902*4882a593Smuzhiyun (s64)ts.tv_sec, ts.tv_nsec);
903*4882a593Smuzhiyun if ((sizeof(h->bootcmd) - strnlen(h->bootcmd, sizeof(h->bootcmd))) <
904*4882a593Smuzhiyun ret) {
905*4882a593Smuzhiyun dev_err(&oct->pci_dev->dev, "Boot command buffer too small\n");
906*4882a593Smuzhiyun return -EINVAL;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun strncat(h->bootcmd, boottime,
909*4882a593Smuzhiyun sizeof(h->bootcmd) - strnlen(h->bootcmd, sizeof(h->bootcmd)));
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "Writing boot command: %s\n",
912*4882a593Smuzhiyun h->bootcmd);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun /* Invoke the bootcmd */
915*4882a593Smuzhiyun ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
916*4882a593Smuzhiyun if (ret)
917*4882a593Smuzhiyun dev_info(&oct->pci_dev->dev, "Boot command send failed\n");
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun return ret;
920*4882a593Smuzhiyun }
921