1f173c2b7SSean Bruno /* 2f173c2b7SSean Bruno * BSD LICENSE 3f173c2b7SSean Bruno * 4f173c2b7SSean Bruno * Copyright(c) 2017 Cavium, Inc.. All rights reserved. 5f173c2b7SSean Bruno * All rights reserved. 6f173c2b7SSean Bruno * 7f173c2b7SSean Bruno * Redistribution and use in source and binary forms, with or without 8f173c2b7SSean Bruno * modification, are permitted provided that the following conditions 9f173c2b7SSean Bruno * are met: 10f173c2b7SSean Bruno * 11f173c2b7SSean Bruno * * Redistributions of source code must retain the above copyright 12f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer. 13f173c2b7SSean Bruno * * Redistributions in binary form must reproduce the above copyright 14f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer in 15f173c2b7SSean Bruno * the documentation and/or other materials provided with the 16f173c2b7SSean Bruno * distribution. 17f173c2b7SSean Bruno * * Neither the name of Cavium, Inc. nor the names of its 18f173c2b7SSean Bruno * contributors may be used to endorse or promote products derived 19f173c2b7SSean Bruno * from this software without specific prior written permission. 20f173c2b7SSean Bruno * 21f173c2b7SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22f173c2b7SSean Bruno * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23f173c2b7SSean Bruno * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24f173c2b7SSean Bruno * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25f173c2b7SSean Bruno * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26f173c2b7SSean Bruno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27f173c2b7SSean Bruno * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28f173c2b7SSean Bruno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29f173c2b7SSean Bruno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30f173c2b7SSean Bruno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31f173c2b7SSean Bruno * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f173c2b7SSean Bruno */ 33f173c2b7SSean Bruno /*$FreeBSD$*/ 34f173c2b7SSean Bruno 35f173c2b7SSean Bruno /* 36f173c2b7SSean Bruno * @file lio_console.c 37f173c2b7SSean Bruno */ 38f173c2b7SSean Bruno 39f173c2b7SSean Bruno #include "lio_bsd.h" 40f173c2b7SSean Bruno #include "lio_common.h" 41f173c2b7SSean Bruno #include "lio_droq.h" 42f173c2b7SSean Bruno #include "lio_iq.h" 43f173c2b7SSean Bruno #include "lio_response_manager.h" 44f173c2b7SSean Bruno #include "lio_device.h" 45f173c2b7SSean Bruno #include "lio_image.h" 46f173c2b7SSean Bruno #include "lio_mem_ops.h" 47f173c2b7SSean Bruno #include "lio_main.h" 48f173c2b7SSean Bruno 49f173c2b7SSean Bruno static void lio_get_uboot_version(struct octeon_device *oct); 50f173c2b7SSean Bruno static void lio_remote_lock(void); 51f173c2b7SSean Bruno static void lio_remote_unlock(void); 52f173c2b7SSean Bruno static uint64_t cvmx_bootmem_phy_named_block_find(struct octeon_device *oct, 53f173c2b7SSean Bruno const char *name, 54f173c2b7SSean Bruno uint32_t flags); 55f173c2b7SSean Bruno static int lio_console_read(struct octeon_device *oct, 56f173c2b7SSean Bruno uint32_t console_num, char *buffer, 57f173c2b7SSean Bruno uint32_t buf_size); 58f173c2b7SSean Bruno 59f173c2b7SSean Bruno #define CAST_ULL(v) ((unsigned long long)(v)) 60f173c2b7SSean Bruno 61f173c2b7SSean Bruno #define LIO_BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR 0x0006c008 62f173c2b7SSean Bruno #define LIO_BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR 0x0006c004 63f173c2b7SSean Bruno #define LIO_BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR 0x0006c000 64f173c2b7SSean Bruno #define LIO_BOOTLOADER_PCI_READ_DESC_ADDR 0x0006c100 65f173c2b7SSean Bruno #define LIO_BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN 248 66f173c2b7SSean Bruno 67f173c2b7SSean Bruno #define LIO_PCI_IO_BUF_OWNER_OCTEON 0x00000001 68f173c2b7SSean Bruno #define LIO_PCI_IO_BUF_OWNER_HOST 0x00000002 69f173c2b7SSean Bruno 70f173c2b7SSean Bruno #define LIO_PCI_CONSOLE_BLOCK_NAME "__pci_console" 71f173c2b7SSean Bruno #define LIO_CONSOLE_POLL_INTERVAL_MS 100 /* 10 times per second */ 72f173c2b7SSean Bruno 73f173c2b7SSean Bruno /* 74f173c2b7SSean Bruno * First three members of cvmx_bootmem_desc are left in original positions 75f173c2b7SSean Bruno * for backwards compatibility. Assumes big endian target 76f173c2b7SSean Bruno */ 77f173c2b7SSean Bruno struct cvmx_bootmem_desc { 78f173c2b7SSean Bruno /* lock to control access to list */ 79f173c2b7SSean Bruno uint32_t lock; 80f173c2b7SSean Bruno 81f173c2b7SSean Bruno /* flags for indicating various conditions */ 82f173c2b7SSean Bruno uint32_t flags; 83f173c2b7SSean Bruno 84f173c2b7SSean Bruno uint64_t head_addr; 85f173c2b7SSean Bruno 86f173c2b7SSean Bruno /* incremented changed when incompatible changes made */ 87f173c2b7SSean Bruno uint32_t major_version; 88f173c2b7SSean Bruno 89f173c2b7SSean Bruno /* 90f173c2b7SSean Bruno * incremented changed when compatible changes made, reset to zero 91f173c2b7SSean Bruno * when major incremented 92f173c2b7SSean Bruno */ 93f173c2b7SSean Bruno uint32_t minor_version; 94f173c2b7SSean Bruno 95f173c2b7SSean Bruno uint64_t app_data_addr; 96f173c2b7SSean Bruno uint64_t app_data_size; 97f173c2b7SSean Bruno 98f173c2b7SSean Bruno /* number of elements in named blocks array */ 99f173c2b7SSean Bruno uint32_t nb_num_blocks; 100f173c2b7SSean Bruno 101f173c2b7SSean Bruno /* length of name array in bootmem blocks */ 102f173c2b7SSean Bruno uint32_t named_block_name_len; 103f173c2b7SSean Bruno 104f173c2b7SSean Bruno /* address of named memory block descriptors */ 105f173c2b7SSean Bruno uint64_t named_block_array_addr; 106f173c2b7SSean Bruno }; 107f173c2b7SSean Bruno 108f173c2b7SSean Bruno /* 109f173c2b7SSean Bruno * Structure that defines a single console. 110f173c2b7SSean Bruno * 111f173c2b7SSean Bruno * Note: when read_index == write_index, the buffer is empty. The actual usable 112f173c2b7SSean Bruno * size of each console is console_buf_size -1; 113f173c2b7SSean Bruno */ 114f173c2b7SSean Bruno struct lio_pci_console { 115f173c2b7SSean Bruno uint64_t input_base_addr; 116f173c2b7SSean Bruno uint32_t input_read_index; 117f173c2b7SSean Bruno uint32_t input_write_index; 118f173c2b7SSean Bruno uint64_t output_base_addr; 119f173c2b7SSean Bruno uint32_t output_read_index; 120f173c2b7SSean Bruno uint32_t output_write_index; 121f173c2b7SSean Bruno uint32_t lock; 122f173c2b7SSean Bruno uint32_t buf_size; 123f173c2b7SSean Bruno }; 124f173c2b7SSean Bruno 125f173c2b7SSean Bruno /* 126f173c2b7SSean Bruno * This is the main container structure that contains all the information 127f173c2b7SSean Bruno * about all PCI consoles. The address of this structure is passed to 128f173c2b7SSean Bruno * various routines that operation on PCI consoles. 129f173c2b7SSean Bruno */ 130f173c2b7SSean Bruno struct lio_pci_console_desc { 131f173c2b7SSean Bruno uint32_t major_version; 132f173c2b7SSean Bruno uint32_t minor_version; 133f173c2b7SSean Bruno uint32_t lock; 134f173c2b7SSean Bruno uint32_t flags; 135f173c2b7SSean Bruno uint32_t num_consoles; 136f173c2b7SSean Bruno uint32_t pad; 137f173c2b7SSean Bruno /* must be 64 bit aligned here... */ 138f173c2b7SSean Bruno /* Array of addresses of octeon_pci_console structures */ 139f173c2b7SSean Bruno uint64_t console_addr_array[1]; 140f173c2b7SSean Bruno /* Implicit storage for console_addr_array */ 141f173c2b7SSean Bruno }; 142f173c2b7SSean Bruno 143f173c2b7SSean Bruno /* 144f173c2b7SSean Bruno * This macro returns the size of a member of a structure. Logically it is 145f173c2b7SSean Bruno * the same as "sizeof(s::field)" in C++, but C lacks the "::" operator. 146f173c2b7SSean Bruno */ 147f173c2b7SSean Bruno #define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field) 148f173c2b7SSean Bruno /* 149f173c2b7SSean Bruno * This function is the implementation of the get macros defined 150f173c2b7SSean Bruno * for individual structure members. The argument are generated 151f173c2b7SSean Bruno * by the macros inorder to read only the needed memory. 152f173c2b7SSean Bruno * 153f173c2b7SSean Bruno * @param oct Pointer to current octeon device 154f173c2b7SSean Bruno * @param base 64bit physical address of the complete structure 155f173c2b7SSean Bruno * @param offset Offset from the beginning of the structure to the member being 156f173c2b7SSean Bruno * accessed. 157f173c2b7SSean Bruno * @param size Size of the structure member. 158f173c2b7SSean Bruno * 159f173c2b7SSean Bruno * @return Value of the structure member promoted into a uint64_t. 160f173c2b7SSean Bruno */ 161f173c2b7SSean Bruno static inline uint64_t 162f173c2b7SSean Bruno __cvmx_bootmem_desc_get(struct octeon_device *oct, uint64_t base, 163f173c2b7SSean Bruno uint32_t offset, uint32_t size) 164f173c2b7SSean Bruno { 165f173c2b7SSean Bruno 166f173c2b7SSean Bruno base = (1ull << 63) | (base + offset); 167f173c2b7SSean Bruno switch (size) { 168f173c2b7SSean Bruno case 4: 169f173c2b7SSean Bruno return (lio_read_device_mem32(oct, base)); 170f173c2b7SSean Bruno case 8: 171f173c2b7SSean Bruno return (lio_read_device_mem64(oct, base)); 172f173c2b7SSean Bruno default: 173f173c2b7SSean Bruno return (0); 174f173c2b7SSean Bruno } 175f173c2b7SSean Bruno } 176f173c2b7SSean Bruno 177f173c2b7SSean Bruno /* 178f173c2b7SSean Bruno * This function retrieves the string name of a named block. It is 179f173c2b7SSean Bruno * more complicated than a simple memcpy() since the named block 180f173c2b7SSean Bruno * descriptor may not be directly accessible. 181f173c2b7SSean Bruno * 182f173c2b7SSean Bruno * @param oct Pointer to current octeon device 183f173c2b7SSean Bruno * @param addr Physical address of the named block descriptor 184f173c2b7SSean Bruno * @param str String to receive the named block string name 185f173c2b7SSean Bruno * @param len Length of the string buffer, which must match the length 186f173c2b7SSean Bruno * stored in the bootmem descriptor. 187f173c2b7SSean Bruno */ 188f173c2b7SSean Bruno static void 189f173c2b7SSean Bruno lio_bootmem_named_get_name(struct octeon_device *oct, uint64_t addr, char *str, 190f173c2b7SSean Bruno uint32_t len) 191f173c2b7SSean Bruno { 192f173c2b7SSean Bruno 193f173c2b7SSean Bruno addr += offsetof(struct cvmx_bootmem_named_block_desc, name); 194f173c2b7SSean Bruno lio_pci_read_core_mem(oct, addr, (uint8_t *) str, len); 195f173c2b7SSean Bruno str[len] = 0; 196f173c2b7SSean Bruno } 197f173c2b7SSean Bruno 198f173c2b7SSean Bruno /* See header file for descriptions of functions */ 199f173c2b7SSean Bruno 200f173c2b7SSean Bruno /* 201f173c2b7SSean Bruno * Check the version information on the bootmem descriptor 202f173c2b7SSean Bruno * 203f173c2b7SSean Bruno * @param oct Pointer to current octeon device 204f173c2b7SSean Bruno * @param exact_match 205f173c2b7SSean Bruno * Exact major version to check against. A zero means 206f173c2b7SSean Bruno * check that the version supports named blocks. 207f173c2b7SSean Bruno * 208f173c2b7SSean Bruno * @return Zero if the version is correct. Negative if the version is 209f173c2b7SSean Bruno * incorrect. Failures also cause a message to be displayed. 210f173c2b7SSean Bruno */ 211f173c2b7SSean Bruno static int 212f173c2b7SSean Bruno __cvmx_bootmem_check_version(struct octeon_device *oct, uint32_t exact_match) 213f173c2b7SSean Bruno { 214f173c2b7SSean Bruno uint32_t major_version; 215f173c2b7SSean Bruno uint32_t minor_version; 216f173c2b7SSean Bruno 217f173c2b7SSean Bruno if (!oct->bootmem_desc_addr) 218f173c2b7SSean Bruno oct->bootmem_desc_addr = 219f173c2b7SSean Bruno lio_read_device_mem64(oct, 220f173c2b7SSean Bruno LIO_BOOTLOADER_PCI_READ_DESC_ADDR); 221f173c2b7SSean Bruno 222f173c2b7SSean Bruno major_version = (uint32_t) __cvmx_bootmem_desc_get(oct, 223f173c2b7SSean Bruno oct->bootmem_desc_addr, 224f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_desc, major_version), 225f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_desc, major_version)); 226f173c2b7SSean Bruno minor_version = (uint32_t) __cvmx_bootmem_desc_get(oct, 227f173c2b7SSean Bruno oct->bootmem_desc_addr, 228f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_desc, minor_version), 229f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_desc, minor_version)); 230f173c2b7SSean Bruno 231f173c2b7SSean Bruno lio_dev_dbg(oct, "%s: major_version=%d\n", __func__, major_version); 232f173c2b7SSean Bruno if ((major_version > 3) || 233f173c2b7SSean Bruno (exact_match && major_version != exact_match)) { 234f173c2b7SSean Bruno lio_dev_err(oct, "bootmem ver mismatch %d.%d addr:0x%llx\n", 235f173c2b7SSean Bruno major_version, minor_version, 236f173c2b7SSean Bruno CAST_ULL(oct->bootmem_desc_addr)); 237f173c2b7SSean Bruno return (-1); 238f173c2b7SSean Bruno } else { 239f173c2b7SSean Bruno return (0); 240f173c2b7SSean Bruno } 241f173c2b7SSean Bruno } 242f173c2b7SSean Bruno 243f173c2b7SSean Bruno static const struct cvmx_bootmem_named_block_desc * 244f173c2b7SSean Bruno __cvmx_bootmem_find_named_block_flags(struct octeon_device *oct, 245f173c2b7SSean Bruno const char *name, uint32_t flags) 246f173c2b7SSean Bruno { 247f173c2b7SSean Bruno struct cvmx_bootmem_named_block_desc *desc = 248f173c2b7SSean Bruno &oct->bootmem_named_block_desc; 249f173c2b7SSean Bruno uint64_t named_addr; 250f173c2b7SSean Bruno 251f173c2b7SSean Bruno named_addr = cvmx_bootmem_phy_named_block_find(oct, name, 252f173c2b7SSean Bruno flags); 253f173c2b7SSean Bruno if (named_addr) { 254f173c2b7SSean Bruno desc->base_addr = __cvmx_bootmem_desc_get(oct, named_addr, 255f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_named_block_desc, 256f173c2b7SSean Bruno base_addr), 257f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, 258f173c2b7SSean Bruno base_addr)); 259f173c2b7SSean Bruno 260f173c2b7SSean Bruno desc->size = __cvmx_bootmem_desc_get(oct, named_addr, 261f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_named_block_desc, size), 262f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, 263f173c2b7SSean Bruno size)); 264f173c2b7SSean Bruno 265f173c2b7SSean Bruno strncpy(desc->name, name, sizeof(desc->name)); 266f173c2b7SSean Bruno desc->name[sizeof(desc->name) - 1] = 0; 267f173c2b7SSean Bruno 268f173c2b7SSean Bruno return (&oct->bootmem_named_block_desc); 269f173c2b7SSean Bruno } else { 270f173c2b7SSean Bruno return (NULL); 271f173c2b7SSean Bruno } 272f173c2b7SSean Bruno } 273f173c2b7SSean Bruno 274f173c2b7SSean Bruno static uint64_t 275f173c2b7SSean Bruno cvmx_bootmem_phy_named_block_find(struct octeon_device *oct, const char *name, 276f173c2b7SSean Bruno uint32_t flags) 277f173c2b7SSean Bruno { 278f173c2b7SSean Bruno uint64_t result = 0; 279f173c2b7SSean Bruno 280f173c2b7SSean Bruno if (!__cvmx_bootmem_check_version(oct, 3)) { 281f173c2b7SSean Bruno uint32_t i; 282f173c2b7SSean Bruno 283f173c2b7SSean Bruno uint64_t named_block_array_addr = 284f173c2b7SSean Bruno __cvmx_bootmem_desc_get(oct, oct->bootmem_desc_addr, 285f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_desc, 286f173c2b7SSean Bruno named_block_array_addr), 287f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_desc, 288f173c2b7SSean Bruno named_block_array_addr)); 289f173c2b7SSean Bruno uint32_t num_blocks = 290f173c2b7SSean Bruno (uint32_t) __cvmx_bootmem_desc_get(oct, 291f173c2b7SSean Bruno oct->bootmem_desc_addr, 292f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_desc, 293f173c2b7SSean Bruno nb_num_blocks), 294f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_desc, 295f173c2b7SSean Bruno nb_num_blocks)); 296f173c2b7SSean Bruno 297f173c2b7SSean Bruno uint32_t name_length = 298f173c2b7SSean Bruno (uint32_t) __cvmx_bootmem_desc_get(oct, 299f173c2b7SSean Bruno oct->bootmem_desc_addr, 300f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_desc, 301f173c2b7SSean Bruno named_block_name_len), 302f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_desc, 303f173c2b7SSean Bruno named_block_name_len)); 304f173c2b7SSean Bruno 305f173c2b7SSean Bruno uint64_t named_addr = named_block_array_addr; 306f173c2b7SSean Bruno 307f173c2b7SSean Bruno for (i = 0; i < num_blocks; i++) { 308f173c2b7SSean Bruno uint64_t named_size = 309f173c2b7SSean Bruno __cvmx_bootmem_desc_get(oct, named_addr, 310f173c2b7SSean Bruno offsetof(struct cvmx_bootmem_named_block_desc, 311f173c2b7SSean Bruno size), 312f173c2b7SSean Bruno SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, 313f173c2b7SSean Bruno size)); 314f173c2b7SSean Bruno 315f173c2b7SSean Bruno if (name && named_size) { 316f173c2b7SSean Bruno char *name_tmp = malloc(name_length + 1, 317f173c2b7SSean Bruno M_DEVBUF, M_NOWAIT | 318f173c2b7SSean Bruno M_ZERO); 319f173c2b7SSean Bruno if (!name_tmp) 320f173c2b7SSean Bruno break; 321f173c2b7SSean Bruno 322f173c2b7SSean Bruno lio_bootmem_named_get_name(oct, named_addr, 323f173c2b7SSean Bruno name_tmp, 324f173c2b7SSean Bruno name_length); 325f173c2b7SSean Bruno 326f173c2b7SSean Bruno if (!strncmp(name, name_tmp, name_length)) { 327f173c2b7SSean Bruno result = named_addr; 328f173c2b7SSean Bruno free(name_tmp, M_DEVBUF); 329f173c2b7SSean Bruno break; 330f173c2b7SSean Bruno } 331f173c2b7SSean Bruno 332f173c2b7SSean Bruno free(name_tmp, M_DEVBUF); 333f173c2b7SSean Bruno 334f173c2b7SSean Bruno } else if (!name && !named_size) { 335f173c2b7SSean Bruno result = named_addr; 336f173c2b7SSean Bruno break; 337f173c2b7SSean Bruno } 338f173c2b7SSean Bruno 339f173c2b7SSean Bruno named_addr += 340f173c2b7SSean Bruno sizeof(struct cvmx_bootmem_named_block_desc); 341f173c2b7SSean Bruno } 342f173c2b7SSean Bruno } 343f173c2b7SSean Bruno return (result); 344f173c2b7SSean Bruno } 345f173c2b7SSean Bruno 346f173c2b7SSean Bruno /* 347f173c2b7SSean Bruno * Find a named block on the remote Octeon 348f173c2b7SSean Bruno * 349f173c2b7SSean Bruno * @param oct Pointer to current octeon device 350f173c2b7SSean Bruno * @param name Name of block to find 351f173c2b7SSean Bruno * @param base_addr Address the block is at (OUTPUT) 352f173c2b7SSean Bruno * @param size The size of the block (OUTPUT) 353f173c2b7SSean Bruno * 354f173c2b7SSean Bruno * @return Zero on success, One on failure. 355f173c2b7SSean Bruno */ 356f173c2b7SSean Bruno static int 357f173c2b7SSean Bruno lio_named_block_find(struct octeon_device *oct, const char *name, 358f173c2b7SSean Bruno uint64_t * base_addr, uint64_t * size) 359f173c2b7SSean Bruno { 360f173c2b7SSean Bruno const struct cvmx_bootmem_named_block_desc *named_block; 361f173c2b7SSean Bruno 362f173c2b7SSean Bruno lio_remote_lock(); 363f173c2b7SSean Bruno named_block = __cvmx_bootmem_find_named_block_flags(oct, name, 0); 364f173c2b7SSean Bruno lio_remote_unlock(); 365f173c2b7SSean Bruno if (named_block != NULL) { 366f173c2b7SSean Bruno *base_addr = named_block->base_addr; 367f173c2b7SSean Bruno *size = named_block->size; 368f173c2b7SSean Bruno return (0); 369f173c2b7SSean Bruno } 370f173c2b7SSean Bruno 371f173c2b7SSean Bruno return (1); 372f173c2b7SSean Bruno } 373f173c2b7SSean Bruno 374f173c2b7SSean Bruno 375f173c2b7SSean Bruno static void 376f173c2b7SSean Bruno lio_remote_lock(void) 377f173c2b7SSean Bruno { 378f173c2b7SSean Bruno 379f173c2b7SSean Bruno /* fill this in if any sharing is needed */ 380f173c2b7SSean Bruno } 381f173c2b7SSean Bruno 382f173c2b7SSean Bruno static void 383f173c2b7SSean Bruno lio_remote_unlock(void) 384f173c2b7SSean Bruno { 385f173c2b7SSean Bruno 386f173c2b7SSean Bruno /* fill this in if any sharing is needed */ 387f173c2b7SSean Bruno } 388f173c2b7SSean Bruno 389f173c2b7SSean Bruno int 390f173c2b7SSean Bruno lio_console_send_cmd(struct octeon_device *oct, char *cmd_str, 391f173c2b7SSean Bruno uint32_t wait_hundredths) 392f173c2b7SSean Bruno { 393f173c2b7SSean Bruno uint32_t len = (uint32_t) strlen(cmd_str); 394f173c2b7SSean Bruno 395f173c2b7SSean Bruno lio_dev_dbg(oct, "sending \"%s\" to bootloader\n", cmd_str); 396f173c2b7SSean Bruno 397f173c2b7SSean Bruno if (len > LIO_BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1) { 398f173c2b7SSean Bruno lio_dev_err(oct, "Command string too long, max length is: %d\n", 399f173c2b7SSean Bruno LIO_BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1); 400f173c2b7SSean Bruno return (-1); 401f173c2b7SSean Bruno } 402f173c2b7SSean Bruno 403f173c2b7SSean Bruno if (lio_wait_for_bootloader(oct, wait_hundredths)) { 404f173c2b7SSean Bruno lio_dev_err(oct, "Bootloader not ready for command.\n"); 405f173c2b7SSean Bruno return (-1); 406f173c2b7SSean Bruno } 407f173c2b7SSean Bruno 408f173c2b7SSean Bruno /* Write command to bootloader */ 409f173c2b7SSean Bruno lio_remote_lock(); 410f173c2b7SSean Bruno lio_pci_write_core_mem(oct, LIO_BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR, 411f173c2b7SSean Bruno (uint8_t *) cmd_str, len); 412f173c2b7SSean Bruno lio_write_device_mem32(oct, LIO_BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR, 413f173c2b7SSean Bruno len); 414f173c2b7SSean Bruno lio_write_device_mem32(oct, LIO_BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR, 415f173c2b7SSean Bruno LIO_PCI_IO_BUF_OWNER_OCTEON); 416f173c2b7SSean Bruno 417f173c2b7SSean Bruno /* 418f173c2b7SSean Bruno * Bootloader should accept command very quickly if it really was 419f173c2b7SSean Bruno * ready 420f173c2b7SSean Bruno */ 421f173c2b7SSean Bruno if (lio_wait_for_bootloader(oct, 200)) { 422f173c2b7SSean Bruno lio_remote_unlock(); 423f173c2b7SSean Bruno lio_dev_err(oct, "Bootloader did not accept command.\n"); 424f173c2b7SSean Bruno return (-1); 425f173c2b7SSean Bruno } 426f173c2b7SSean Bruno 427f173c2b7SSean Bruno lio_remote_unlock(); 428f173c2b7SSean Bruno return (0); 429f173c2b7SSean Bruno } 430f173c2b7SSean Bruno 431f173c2b7SSean Bruno int 432f173c2b7SSean Bruno lio_wait_for_bootloader(struct octeon_device *oct, 433f173c2b7SSean Bruno uint32_t wait_time_hundredths) 434f173c2b7SSean Bruno { 435f173c2b7SSean Bruno lio_dev_dbg(oct, "waiting %d0 ms for bootloader\n", 436f173c2b7SSean Bruno wait_time_hundredths); 437f173c2b7SSean Bruno 438f173c2b7SSean Bruno if (lio_mem_access_ok(oct)) 439f173c2b7SSean Bruno return (-1); 440f173c2b7SSean Bruno 441f173c2b7SSean Bruno while (wait_time_hundredths > 0 && 442f173c2b7SSean Bruno lio_read_device_mem32(oct, 443f173c2b7SSean Bruno LIO_BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR) != 444f173c2b7SSean Bruno LIO_PCI_IO_BUF_OWNER_HOST) { 445f173c2b7SSean Bruno if (--wait_time_hundredths <= 0) 446f173c2b7SSean Bruno return (-1); 447f173c2b7SSean Bruno 448f173c2b7SSean Bruno lio_sleep_timeout(10); 449f173c2b7SSean Bruno } 450f173c2b7SSean Bruno 451f173c2b7SSean Bruno return (0); 452f173c2b7SSean Bruno } 453f173c2b7SSean Bruno 454f173c2b7SSean Bruno static void 455f173c2b7SSean Bruno lio_console_handle_result(struct octeon_device *oct, size_t console_num) 456f173c2b7SSean Bruno { 457f173c2b7SSean Bruno struct lio_console *console; 458f173c2b7SSean Bruno 459f173c2b7SSean Bruno console = &oct->console[console_num]; 460f173c2b7SSean Bruno 461f173c2b7SSean Bruno console->waiting = 0; 462f173c2b7SSean Bruno } 463f173c2b7SSean Bruno 464f173c2b7SSean Bruno static char console_buffer[LIO_MAX_CONSOLE_READ_BYTES]; 465f173c2b7SSean Bruno 466f173c2b7SSean Bruno static void 467f173c2b7SSean Bruno lio_output_console_line(struct octeon_device *oct, struct lio_console *console, 468f173c2b7SSean Bruno size_t console_num, char *console_buffer, 469f173c2b7SSean Bruno int32_t bytes_read) 470f173c2b7SSean Bruno { 471f173c2b7SSean Bruno size_t len; 472f173c2b7SSean Bruno int32_t i; 473f173c2b7SSean Bruno char *line; 474f173c2b7SSean Bruno 475f173c2b7SSean Bruno line = console_buffer; 476f173c2b7SSean Bruno for (i = 0; i < bytes_read; i++) { 477f173c2b7SSean Bruno /* Output a line at a time, prefixed */ 478f173c2b7SSean Bruno if (console_buffer[i] == '\n') { 479f173c2b7SSean Bruno console_buffer[i] = '\0'; 480f173c2b7SSean Bruno /* We need to output 'line', prefaced by 'leftover'. 481f173c2b7SSean Bruno * However, it is possible we're being called to 482f173c2b7SSean Bruno * output 'leftover' by itself (in the case of nothing 483f173c2b7SSean Bruno * having been read from the console). 484f173c2b7SSean Bruno * 485f173c2b7SSean Bruno * To avoid duplication, check for this condition. 486f173c2b7SSean Bruno */ 487f173c2b7SSean Bruno if (console->leftover[0] && 488f173c2b7SSean Bruno (line != console->leftover)) { 489f173c2b7SSean Bruno if (console->print) 490f173c2b7SSean Bruno (*console->print)(oct, 491f173c2b7SSean Bruno (uint32_t)console_num, 492f173c2b7SSean Bruno console->leftover,line); 493f173c2b7SSean Bruno console->leftover[0] = '\0'; 494f173c2b7SSean Bruno } else { 495f173c2b7SSean Bruno if (console->print) 496f173c2b7SSean Bruno (*console->print)(oct, 497f173c2b7SSean Bruno (uint32_t)console_num, 498f173c2b7SSean Bruno line, NULL); 499f173c2b7SSean Bruno } 500f173c2b7SSean Bruno 501f173c2b7SSean Bruno line = &console_buffer[i + 1]; 502f173c2b7SSean Bruno } 503f173c2b7SSean Bruno } 504f173c2b7SSean Bruno 505f173c2b7SSean Bruno /* Save off any leftovers */ 506f173c2b7SSean Bruno if (line != &console_buffer[bytes_read]) { 507f173c2b7SSean Bruno console_buffer[bytes_read] = '\0'; 508f173c2b7SSean Bruno len = strlen(console->leftover); 509f173c2b7SSean Bruno strncpy(&console->leftover[len], line, 510f173c2b7SSean Bruno sizeof(console->leftover) - len); 511f173c2b7SSean Bruno } 512f173c2b7SSean Bruno } 513f173c2b7SSean Bruno 514f173c2b7SSean Bruno static void 515f173c2b7SSean Bruno lio_check_console(void *arg) 516f173c2b7SSean Bruno { 517f173c2b7SSean Bruno struct lio_console *console; 518f173c2b7SSean Bruno struct lio_callout *console_callout = arg; 519f173c2b7SSean Bruno struct octeon_device *oct = 520f173c2b7SSean Bruno (struct octeon_device *)console_callout->ctxptr; 521f173c2b7SSean Bruno size_t len; 522f173c2b7SSean Bruno uint32_t console_num = (uint32_t) console_callout->ctxul; 523f173c2b7SSean Bruno int32_t bytes_read, total_read, tries; 524f173c2b7SSean Bruno 525f173c2b7SSean Bruno console = &oct->console[console_num]; 526f173c2b7SSean Bruno tries = 0; 527f173c2b7SSean Bruno total_read = 0; 528f173c2b7SSean Bruno 529f173c2b7SSean Bruno if (callout_pending(&console_callout->timer) || 530f173c2b7SSean Bruno (callout_active(&console_callout->timer) == 0)) 531f173c2b7SSean Bruno return; 532f173c2b7SSean Bruno 533f173c2b7SSean Bruno do { 534f173c2b7SSean Bruno /* 535f173c2b7SSean Bruno * Take console output regardless of whether it will be 536f173c2b7SSean Bruno * logged 537f173c2b7SSean Bruno */ 538f173c2b7SSean Bruno bytes_read = lio_console_read(oct, console_num, console_buffer, 539f173c2b7SSean Bruno sizeof(console_buffer) - 1); 540f173c2b7SSean Bruno if (bytes_read > 0) { 541f173c2b7SSean Bruno total_read += bytes_read; 542f173c2b7SSean Bruno if (console->waiting) 543f173c2b7SSean Bruno lio_console_handle_result(oct, console_num); 544f173c2b7SSean Bruno 545f173c2b7SSean Bruno if (console->print) { 546f173c2b7SSean Bruno lio_output_console_line(oct, console, 547f173c2b7SSean Bruno console_num, 548f173c2b7SSean Bruno console_buffer, 549f173c2b7SSean Bruno bytes_read); 550f173c2b7SSean Bruno } 551f173c2b7SSean Bruno 552f173c2b7SSean Bruno } else if (bytes_read < 0) { 553f173c2b7SSean Bruno lio_dev_err(oct, "Error reading console %u, ret=%d\n", 554f173c2b7SSean Bruno console_num, bytes_read); 555f173c2b7SSean Bruno } 556f173c2b7SSean Bruno 557f173c2b7SSean Bruno tries++; 558f173c2b7SSean Bruno } while ((bytes_read > 0) && (tries < 16)); 559f173c2b7SSean Bruno 560f173c2b7SSean Bruno /* 561f173c2b7SSean Bruno * If nothing is read after polling the console, output any leftovers 562f173c2b7SSean Bruno * if any 563f173c2b7SSean Bruno */ 564f173c2b7SSean Bruno if (console->print && (total_read == 0) && (console->leftover[0])) { 565f173c2b7SSean Bruno /* append '\n' as terminator for 'output_console_line' */ 566f173c2b7SSean Bruno len = strlen(console->leftover); 567f173c2b7SSean Bruno console->leftover[len] = '\n'; 568f173c2b7SSean Bruno lio_output_console_line(oct, console, console_num, 569f173c2b7SSean Bruno console->leftover, (int32_t)(len + 1)); 570f173c2b7SSean Bruno console->leftover[0] = '\0'; 571f173c2b7SSean Bruno } 572f173c2b7SSean Bruno callout_schedule(&oct->console_timer[console_num].timer, 573f173c2b7SSean Bruno lio_ms_to_ticks(LIO_CONSOLE_POLL_INTERVAL_MS)); 574f173c2b7SSean Bruno } 575f173c2b7SSean Bruno 576f173c2b7SSean Bruno 577f173c2b7SSean Bruno int 578f173c2b7SSean Bruno lio_init_consoles(struct octeon_device *oct) 579f173c2b7SSean Bruno { 580f173c2b7SSean Bruno uint64_t addr, size; 581f173c2b7SSean Bruno int ret = 0; 582f173c2b7SSean Bruno 583f173c2b7SSean Bruno ret = lio_mem_access_ok(oct); 584f173c2b7SSean Bruno if (ret) { 585f173c2b7SSean Bruno lio_dev_err(oct, "Memory access not okay'\n"); 586f173c2b7SSean Bruno return (ret); 587f173c2b7SSean Bruno } 588f173c2b7SSean Bruno ret = lio_named_block_find(oct, LIO_PCI_CONSOLE_BLOCK_NAME, &addr, 589f173c2b7SSean Bruno &size); 590f173c2b7SSean Bruno if (ret) { 591f173c2b7SSean Bruno lio_dev_err(oct, "Could not find console '%s'\n", 592f173c2b7SSean Bruno LIO_PCI_CONSOLE_BLOCK_NAME); 593f173c2b7SSean Bruno return (ret); 594f173c2b7SSean Bruno } 595f173c2b7SSean Bruno 596f173c2b7SSean Bruno /* 597f173c2b7SSean Bruno * Use BAR1_INDEX15 to create a static mapping to a region of 598f173c2b7SSean Bruno * Octeon's DRAM that contains the PCI console named block. 599f173c2b7SSean Bruno */ 600f173c2b7SSean Bruno oct->console_nb_info.bar1_index = 15; 601f173c2b7SSean Bruno oct->fn_list.bar1_idx_setup(oct, addr, oct->console_nb_info.bar1_index, 602f173c2b7SSean Bruno 1); 603f173c2b7SSean Bruno oct->console_nb_info.dram_region_base = addr & 0xFFFFFFFFFFC00000ULL; 604f173c2b7SSean Bruno 605f173c2b7SSean Bruno /* 606f173c2b7SSean Bruno * num_consoles > 0, is an indication that the consoles are 607f173c2b7SSean Bruno * accessible 608f173c2b7SSean Bruno */ 609f173c2b7SSean Bruno oct->num_consoles = lio_read_device_mem32(oct, 610f173c2b7SSean Bruno addr + offsetof(struct lio_pci_console_desc, 611f173c2b7SSean Bruno num_consoles)); 612f173c2b7SSean Bruno oct->console_desc_addr = addr; 613f173c2b7SSean Bruno 614f173c2b7SSean Bruno lio_dev_dbg(oct, "Initialized consoles. %d available\n", 615f173c2b7SSean Bruno oct->num_consoles); 616f173c2b7SSean Bruno 617f173c2b7SSean Bruno return (ret); 618f173c2b7SSean Bruno } 619f173c2b7SSean Bruno 620f173c2b7SSean Bruno int 621f173c2b7SSean Bruno lio_add_console(struct octeon_device *oct, uint32_t console_num, char *dbg_enb) 622f173c2b7SSean Bruno { 623f173c2b7SSean Bruno struct callout *timer; 624f173c2b7SSean Bruno struct lio_console *console; 625f173c2b7SSean Bruno uint64_t coreaddr; 626f173c2b7SSean Bruno int ret = 0; 627f173c2b7SSean Bruno 628f173c2b7SSean Bruno if (console_num >= oct->num_consoles) { 629f173c2b7SSean Bruno lio_dev_err(oct, "trying to read from console number %d when only 0 to %d exist\n", 630f173c2b7SSean Bruno console_num, oct->num_consoles); 631f173c2b7SSean Bruno } else { 632f173c2b7SSean Bruno console = &oct->console[console_num]; 633f173c2b7SSean Bruno 634f173c2b7SSean Bruno console->waiting = 0; 635f173c2b7SSean Bruno 636f173c2b7SSean Bruno coreaddr = oct->console_desc_addr + console_num * 8 + 637f173c2b7SSean Bruno offsetof(struct lio_pci_console_desc, 638f173c2b7SSean Bruno console_addr_array); 639f173c2b7SSean Bruno console->addr = lio_read_device_mem64(oct, coreaddr); 640f173c2b7SSean Bruno coreaddr = console->addr + offsetof(struct lio_pci_console, 641f173c2b7SSean Bruno buf_size); 642f173c2b7SSean Bruno console->buffer_size = lio_read_device_mem32(oct, coreaddr); 643f173c2b7SSean Bruno coreaddr = console->addr + offsetof(struct lio_pci_console, 644f173c2b7SSean Bruno input_base_addr); 645f173c2b7SSean Bruno console->input_base_addr = lio_read_device_mem64(oct, coreaddr); 646f173c2b7SSean Bruno coreaddr = console->addr + offsetof(struct lio_pci_console, 647f173c2b7SSean Bruno output_base_addr); 648f173c2b7SSean Bruno console->output_base_addr = 649f173c2b7SSean Bruno lio_read_device_mem64(oct, coreaddr); 650f173c2b7SSean Bruno console->leftover[0] = '\0'; 651f173c2b7SSean Bruno 652f173c2b7SSean Bruno timer = &oct->console_timer[console_num].timer; 653f173c2b7SSean Bruno 654f173c2b7SSean Bruno if (oct->uboot_len == 0) 655f173c2b7SSean Bruno lio_get_uboot_version(oct); 656f173c2b7SSean Bruno 657f173c2b7SSean Bruno callout_init(timer, 0); 658f173c2b7SSean Bruno oct->console_timer[console_num].ctxptr = (void *)oct; 659f173c2b7SSean Bruno oct->console_timer[console_num].ctxul = console_num; 660f173c2b7SSean Bruno callout_reset(timer, 661f173c2b7SSean Bruno lio_ms_to_ticks(LIO_CONSOLE_POLL_INTERVAL_MS), 662f173c2b7SSean Bruno lio_check_console, timer); 663f173c2b7SSean Bruno /* an empty string means use default debug console enablement */ 664f173c2b7SSean Bruno if (dbg_enb && !dbg_enb[0]) 665f173c2b7SSean Bruno dbg_enb = "setenv pci_console_active 1"; 666f173c2b7SSean Bruno 667f173c2b7SSean Bruno if (dbg_enb) 668f173c2b7SSean Bruno ret = lio_console_send_cmd(oct, dbg_enb, 2000); 669f173c2b7SSean Bruno 670f173c2b7SSean Bruno console->active = 1; 671f173c2b7SSean Bruno } 672f173c2b7SSean Bruno 673f173c2b7SSean Bruno return (ret); 674f173c2b7SSean Bruno } 675f173c2b7SSean Bruno 676f173c2b7SSean Bruno /* 677f173c2b7SSean Bruno * Removes all consoles 678f173c2b7SSean Bruno * 679f173c2b7SSean Bruno * @param oct octeon device 680f173c2b7SSean Bruno */ 681f173c2b7SSean Bruno void 682f173c2b7SSean Bruno lio_remove_consoles(struct octeon_device *oct) 683f173c2b7SSean Bruno { 684f173c2b7SSean Bruno struct lio_console *console; 685f173c2b7SSean Bruno uint32_t i; 686f173c2b7SSean Bruno 687f173c2b7SSean Bruno for (i = 0; i < oct->num_consoles; i++) { 688f173c2b7SSean Bruno console = &oct->console[i]; 689f173c2b7SSean Bruno 690f173c2b7SSean Bruno if (!console->active) 691f173c2b7SSean Bruno continue; 692f173c2b7SSean Bruno 693f173c2b7SSean Bruno callout_stop(&oct->console_timer[i].timer); 694f173c2b7SSean Bruno console->addr = 0; 695f173c2b7SSean Bruno console->buffer_size = 0; 696f173c2b7SSean Bruno console->input_base_addr = 0; 697f173c2b7SSean Bruno console->output_base_addr = 0; 698f173c2b7SSean Bruno } 699f173c2b7SSean Bruno 700f173c2b7SSean Bruno oct->num_consoles = 0; 701f173c2b7SSean Bruno } 702f173c2b7SSean Bruno 703f173c2b7SSean Bruno static inline int 704f173c2b7SSean Bruno lio_console_free_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx) 705f173c2b7SSean Bruno { 706f173c2b7SSean Bruno 707f173c2b7SSean Bruno if (rd_idx >= buffer_size || wr_idx >= buffer_size) 708f173c2b7SSean Bruno return (-1); 709f173c2b7SSean Bruno 710f173c2b7SSean Bruno return (((buffer_size - 1) - (wr_idx - rd_idx)) % buffer_size); 711f173c2b7SSean Bruno } 712f173c2b7SSean Bruno 713f173c2b7SSean Bruno static inline int 714f173c2b7SSean Bruno lio_console_avail_bytes(uint32_t buffer_size, uint32_t wr_idx, uint32_t rd_idx) 715f173c2b7SSean Bruno { 716f173c2b7SSean Bruno 717f173c2b7SSean Bruno if (rd_idx >= buffer_size || wr_idx >= buffer_size) 718f173c2b7SSean Bruno return (-1); 719f173c2b7SSean Bruno 720f173c2b7SSean Bruno return (buffer_size - 1 - 721f173c2b7SSean Bruno lio_console_free_bytes(buffer_size, wr_idx, rd_idx)); 722f173c2b7SSean Bruno } 723f173c2b7SSean Bruno 724f173c2b7SSean Bruno static int 725f173c2b7SSean Bruno lio_console_read(struct octeon_device *oct, uint32_t console_num, char *buffer, 726f173c2b7SSean Bruno uint32_t buf_size) 727f173c2b7SSean Bruno { 728f173c2b7SSean Bruno struct lio_console *console; 729f173c2b7SSean Bruno int bytes_to_read; 730f173c2b7SSean Bruno uint32_t rd_idx, wr_idx; 731f173c2b7SSean Bruno 732f173c2b7SSean Bruno if (console_num >= oct->num_consoles) { 733f173c2b7SSean Bruno lio_dev_err(oct, "Attempted to read from disabled console %d\n", 734f173c2b7SSean Bruno console_num); 735f173c2b7SSean Bruno return (0); 736f173c2b7SSean Bruno } 737f173c2b7SSean Bruno 738f173c2b7SSean Bruno console = &oct->console[console_num]; 739f173c2b7SSean Bruno 740f173c2b7SSean Bruno /* 741f173c2b7SSean Bruno * Check to see if any data is available. Maybe optimize this with 742f173c2b7SSean Bruno * 64-bit read. 743f173c2b7SSean Bruno */ 744f173c2b7SSean Bruno rd_idx = lio_read_device_mem32(oct, console->addr + 745f173c2b7SSean Bruno offsetof(struct lio_pci_console, output_read_index)); 746f173c2b7SSean Bruno wr_idx = lio_read_device_mem32(oct, console->addr + 747f173c2b7SSean Bruno offsetof(struct lio_pci_console, output_write_index)); 748f173c2b7SSean Bruno 749f173c2b7SSean Bruno bytes_to_read = lio_console_avail_bytes(console->buffer_size, 750f173c2b7SSean Bruno wr_idx, rd_idx); 751f173c2b7SSean Bruno if (bytes_to_read <= 0) 752f173c2b7SSean Bruno return (bytes_to_read); 753f173c2b7SSean Bruno 754f173c2b7SSean Bruno bytes_to_read = min(bytes_to_read, buf_size); 755f173c2b7SSean Bruno 756f173c2b7SSean Bruno /* 757f173c2b7SSean Bruno * Check to see if what we want to read is not contiguous, and limit 758f173c2b7SSean Bruno * ourselves to the contiguous block 759f173c2b7SSean Bruno */ 760f173c2b7SSean Bruno if (rd_idx + bytes_to_read >= console->buffer_size) 761f173c2b7SSean Bruno bytes_to_read = console->buffer_size - rd_idx; 762f173c2b7SSean Bruno 763f173c2b7SSean Bruno lio_pci_read_core_mem(oct, console->output_base_addr + rd_idx, 764f173c2b7SSean Bruno (uint8_t *) buffer, bytes_to_read); 765f173c2b7SSean Bruno lio_write_device_mem32(oct, console->addr + 766f173c2b7SSean Bruno offsetof(struct lio_pci_console, 767f173c2b7SSean Bruno output_read_index), 768f173c2b7SSean Bruno (rd_idx + bytes_to_read) % console->buffer_size); 769f173c2b7SSean Bruno 770f173c2b7SSean Bruno return (bytes_to_read); 771f173c2b7SSean Bruno } 772f173c2b7SSean Bruno 773f173c2b7SSean Bruno static void 774f173c2b7SSean Bruno lio_get_uboot_version(struct octeon_device *oct) 775f173c2b7SSean Bruno { 776f173c2b7SSean Bruno struct lio_console *console; 777f173c2b7SSean Bruno int32_t bytes_read, total_read, tries; 778f173c2b7SSean Bruno uint32_t console_num = 0; 779*8af24219SJohn Baldwin int i, ret __unused = 0; 780f173c2b7SSean Bruno 781f173c2b7SSean Bruno ret = lio_console_send_cmd(oct, "setenv stdout pci", 50); 782f173c2b7SSean Bruno 783f173c2b7SSean Bruno console = &oct->console[console_num]; 784f173c2b7SSean Bruno tries = 0; 785f173c2b7SSean Bruno total_read = 0; 786f173c2b7SSean Bruno 787f173c2b7SSean Bruno ret = lio_console_send_cmd(oct, "version", 1); 788f173c2b7SSean Bruno 789f173c2b7SSean Bruno do { 790f173c2b7SSean Bruno /* 791f173c2b7SSean Bruno * Take console output regardless of whether it will be 792f173c2b7SSean Bruno * logged 793f173c2b7SSean Bruno */ 794f173c2b7SSean Bruno bytes_read = lio_console_read(oct, 795f173c2b7SSean Bruno console_num, oct->uboot_version + 796f173c2b7SSean Bruno total_read, 797f173c2b7SSean Bruno OCTEON_UBOOT_BUFFER_SIZE - 1 - 798f173c2b7SSean Bruno total_read); 799f173c2b7SSean Bruno if (bytes_read > 0) { 800f173c2b7SSean Bruno oct->uboot_version[bytes_read] = 0x0; 801f173c2b7SSean Bruno 802f173c2b7SSean Bruno total_read += bytes_read; 803f173c2b7SSean Bruno if (console->waiting) 804f173c2b7SSean Bruno lio_console_handle_result(oct, console_num); 805f173c2b7SSean Bruno 806f173c2b7SSean Bruno } else if (bytes_read < 0) { 807f173c2b7SSean Bruno lio_dev_err(oct, "Error reading console %u, ret=%d\n", 808f173c2b7SSean Bruno console_num, bytes_read); 809f173c2b7SSean Bruno } 810f173c2b7SSean Bruno 811f173c2b7SSean Bruno tries++; 812f173c2b7SSean Bruno } while ((bytes_read > 0) && (tries < 16)); 813f173c2b7SSean Bruno 814f173c2b7SSean Bruno /* 815f173c2b7SSean Bruno * If nothing is read after polling the console, output any leftovers 816f173c2b7SSean Bruno * if any 817f173c2b7SSean Bruno */ 818f173c2b7SSean Bruno if ((total_read == 0) && (console->leftover[0])) { 819f173c2b7SSean Bruno lio_dev_dbg(oct, "%u: %s\n", console_num, console->leftover); 820f173c2b7SSean Bruno console->leftover[0] = '\0'; 821f173c2b7SSean Bruno } 822f173c2b7SSean Bruno 823f173c2b7SSean Bruno ret = lio_console_send_cmd(oct, "setenv stdout serial", 50); 824f173c2b7SSean Bruno 825f173c2b7SSean Bruno /* U-Boot */ 826f173c2b7SSean Bruno for (i = 0; i < (OCTEON_UBOOT_BUFFER_SIZE - 9); i++) { 827f173c2b7SSean Bruno if (oct->uboot_version[i] == 'U' && 828f173c2b7SSean Bruno oct->uboot_version[i + 2] == 'B' && 829f173c2b7SSean Bruno oct->uboot_version[i + 3] == 'o' && 830f173c2b7SSean Bruno oct->uboot_version[i + 4] == 'o' && 831f173c2b7SSean Bruno oct->uboot_version[i + 5] == 't') { 832f173c2b7SSean Bruno oct->uboot_sidx = i; 833f173c2b7SSean Bruno i++; 834f173c2b7SSean Bruno for (; oct->uboot_version[i] != 0x0; i++) { 835f173c2b7SSean Bruno if (oct->uboot_version[i] == 'm' && 836f173c2b7SSean Bruno oct->uboot_version[i + 1] == 'i' && 837f173c2b7SSean Bruno oct->uboot_version[i + 2] == 'p' && 838f173c2b7SSean Bruno oct->uboot_version[i + 3] == 's') { 839f173c2b7SSean Bruno oct->uboot_eidx = i - 1; 840f173c2b7SSean Bruno oct->uboot_version[i - 1] = 0x0; 841f173c2b7SSean Bruno oct->uboot_len = oct->uboot_eidx - 842f173c2b7SSean Bruno oct->uboot_sidx + 1; 843f173c2b7SSean Bruno lio_dev_info(oct, "%s\n", 844f173c2b7SSean Bruno &oct->uboot_version 845f173c2b7SSean Bruno [oct->uboot_sidx]); 846f173c2b7SSean Bruno return; 847f173c2b7SSean Bruno } 848f173c2b7SSean Bruno } 849f173c2b7SSean Bruno } 850f173c2b7SSean Bruno } 851f173c2b7SSean Bruno } 852f173c2b7SSean Bruno 853f173c2b7SSean Bruno 854f173c2b7SSean Bruno #define FBUF_SIZE (4 * 1024 * 1024) 855f173c2b7SSean Bruno 856f173c2b7SSean Bruno int 857f173c2b7SSean Bruno lio_download_firmware(struct octeon_device *oct, const uint8_t * data, 858f173c2b7SSean Bruno size_t size) 859f173c2b7SSean Bruno { 860f173c2b7SSean Bruno struct lio_firmware_file_header *h; 861f173c2b7SSean Bruno uint64_t load_addr; 862f173c2b7SSean Bruno uint32_t crc32_result, i, image_len, rem; 863f173c2b7SSean Bruno 864f173c2b7SSean Bruno if (size < sizeof(struct lio_firmware_file_header)) { 865f173c2b7SSean Bruno lio_dev_err(oct, "Firmware file too small (%d < %d).\n", 866f173c2b7SSean Bruno (uint32_t) size, 867f173c2b7SSean Bruno (uint32_t) sizeof(struct lio_firmware_file_header)); 868f173c2b7SSean Bruno return (-EINVAL); 869f173c2b7SSean Bruno } 870f173c2b7SSean Bruno 871f173c2b7SSean Bruno h = __DECONST(struct lio_firmware_file_header *, data); 872f173c2b7SSean Bruno 873f173c2b7SSean Bruno if (be32toh(h->magic) != LIO_NIC_MAGIC) { 874f173c2b7SSean Bruno lio_dev_err(oct, "Unrecognized firmware file.\n"); 875f173c2b7SSean Bruno return (-EINVAL); 876f173c2b7SSean Bruno } 877f173c2b7SSean Bruno 878f173c2b7SSean Bruno crc32_result = crc32(data, sizeof(struct lio_firmware_file_header) - 879f173c2b7SSean Bruno sizeof(uint32_t)); 880f173c2b7SSean Bruno if (crc32_result != be32toh(h->crc32)) { 881f173c2b7SSean Bruno lio_dev_err(oct, "Firmware CRC mismatch (0x%08x != 0x%08x).\n", 882f173c2b7SSean Bruno crc32_result, be32toh(h->crc32)); 883f173c2b7SSean Bruno return (-EINVAL); 884f173c2b7SSean Bruno } 885f173c2b7SSean Bruno 886f173c2b7SSean Bruno if (memcmp(LIO_BASE_VERSION, h->version, 887f173c2b7SSean Bruno strlen(LIO_BASE_VERSION))) { 888f173c2b7SSean Bruno lio_dev_err(oct, "Unmatched firmware version. Expected %s.x, got %s.\n", 889f173c2b7SSean Bruno LIO_BASE_VERSION, h->version); 890f173c2b7SSean Bruno return (-EINVAL); 891f173c2b7SSean Bruno } 892f173c2b7SSean Bruno 893f173c2b7SSean Bruno if (be32toh(h->num_images) > LIO_MAX_IMAGES) { 894f173c2b7SSean Bruno lio_dev_err(oct, "Too many images in firmware file (%d).\n", 895f173c2b7SSean Bruno be32toh(h->num_images)); 896f173c2b7SSean Bruno return (-EINVAL); 897f173c2b7SSean Bruno } 898f173c2b7SSean Bruno 899f173c2b7SSean Bruno lio_dev_info(oct, "Firmware version: %s\n", h->version); 900f173c2b7SSean Bruno snprintf(oct->fw_info.lio_firmware_version, 32, "LIQUIDIO: %s", 901f173c2b7SSean Bruno h->version); 902f173c2b7SSean Bruno 903f173c2b7SSean Bruno data += sizeof(struct lio_firmware_file_header); 904f173c2b7SSean Bruno 905f173c2b7SSean Bruno lio_dev_info(oct, "Loading %d image(s)\n", be32toh(h->num_images)); 906f173c2b7SSean Bruno 907f173c2b7SSean Bruno /* load all images */ 908f173c2b7SSean Bruno for (i = 0; i < be32toh(h->num_images); i++) { 909f173c2b7SSean Bruno load_addr = be64toh(h->desc[i].addr); 910f173c2b7SSean Bruno image_len = be32toh(h->desc[i].len); 911f173c2b7SSean Bruno 912f173c2b7SSean Bruno lio_dev_info(oct, "Loading firmware %d at %llx\n", image_len, 913f173c2b7SSean Bruno (unsigned long long)load_addr); 914f173c2b7SSean Bruno 915f173c2b7SSean Bruno /* Write in 4MB chunks */ 916f173c2b7SSean Bruno rem = image_len; 917f173c2b7SSean Bruno 918f173c2b7SSean Bruno while (rem) { 919f173c2b7SSean Bruno if (rem < FBUF_SIZE) 920f173c2b7SSean Bruno size = rem; 921f173c2b7SSean Bruno else 922f173c2b7SSean Bruno size = FBUF_SIZE; 923f173c2b7SSean Bruno 924f173c2b7SSean Bruno /* download the image */ 925f173c2b7SSean Bruno lio_pci_write_core_mem(oct, load_addr, 926f173c2b7SSean Bruno __DECONST(uint8_t *, data), 927f173c2b7SSean Bruno (uint32_t) size); 928f173c2b7SSean Bruno 929f173c2b7SSean Bruno data += size; 930f173c2b7SSean Bruno rem -= (uint32_t) size; 931f173c2b7SSean Bruno load_addr += size; 932f173c2b7SSean Bruno } 933f173c2b7SSean Bruno } 934f173c2b7SSean Bruno 935f173c2b7SSean Bruno lio_dev_info(oct, "Writing boot command: %s\n", h->bootcmd); 936f173c2b7SSean Bruno 937f173c2b7SSean Bruno /* Invoke the bootcmd */ 938*8af24219SJohn Baldwin lio_console_send_cmd(oct, h->bootcmd, 50); 939f173c2b7SSean Bruno return (0); 940f173c2b7SSean Bruno } 941