xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/cavium/liquidio/octeon_console.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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