diff options
Diffstat (limited to 'src')
29 files changed, 2757 insertions, 154 deletions
diff --git a/src/Makefile b/src/Makefile index bc82cc6f..95719628 100644 --- a/src/Makefile +++ b/src/Makefile @@ -77,6 +77,7 @@ SRCDIRS += drivers/net/efi SRCDIRS += drivers/net/tg3 SRCDIRS += drivers/net/bnxt SRCDIRS += drivers/net/sfc +SRCDIRS += drivers/net/marvell SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash diff --git a/src/arch/x86/interface/pcbios/vesafb.c b/src/arch/x86/interface/pcbios/vesafb.c index 86edbda4..3ca15271 100644 --- a/src/arch/x86/interface/pcbios/vesafb.c +++ b/src/arch/x86/interface/pcbios/vesafb.c @@ -151,8 +151,140 @@ static void vesafb_glyph ( unsigned int character, uint8_t *glyph ) { /* ASCII character: use corresponding glyph */ index = character; } else { - /* Non-ASCII character: use "unknown" glyph */ - index = VESAFB_UNKNOWN; + switch ( character ) { + /* above ASCII */ + case 0xc7: index = 0x80; break; + case 0xfc: index = 0x81; break; + case 0xe9: index = 0x82; break; + case 0xe2: index = 0x83; break; + case 0xe4: index = 0x84; break; + case 0xe0: index = 0x85; break; + case 0xe5: index = 0x86; break; + case 0xe7: index = 0x87; break; + case 0xea: index = 0x88; break; + case 0xeb: index = 0x89; break; + case 0xe8: index = 0x8a; break; + case 0xef: index = 0x8b; break; + case 0xee: index = 0x8c; break; + case 0xec: index = 0x8d; break; + case 0xc4: index = 0x8e; break; + case 0xc5: index = 0x8f; break; + case 0xc9: index = 0x90; break; + case 0xe6: index = 0x91; break; + case 0xc6: index = 0x92; break; + case 0xf4: index = 0x93; break; + case 0xf6: index = 0x94; break; + case 0xf2: index = 0x95; break; + case 0xfb: index = 0x96; break; + case 0xf9: index = 0x97; break; + case 0xff: index = 0x98; break; + case 0xd6: index = 0x99; break; + case 0xdc: index = 0x9a; break; + case 0xa2: index = 0x9b; break; + case 0xa3: index = 0x9c; break; + case 0xa5: index = 0x9d; break; + case 0x20a7: index = 0x9e; break; + case 0x192: index = 0x9f; break; + case 0xe1: index = 0xa0; break; + case 0xed: index = 0xa1; break; + case 0xf3: index = 0xa2; break; + case 0xfa: index = 0xa3; break; + case 0xf1: index = 0xa4; break; + case 0xd1: index = 0xa5; break; + case 0xaa: index = 0xa6; break; + case 0xba: index = 0xa7; break; + case 0xbf: index = 0xa8; break; + case 0x2310: index = 0xa9; break; + case 0xac: index = 0xaa; break; + case 0xbd: index = 0xab; break; + case 0xbc: index = 0xac; break; + case 0xa1: index = 0xad; break; + case 0xab: index = 0xae; break; + case 0xbb: index = 0xaf; break; + case 0x2591: index = 0xb0; break; + case 0x2592: index = 0xb1; break; + case 0x2593: index = 0xb2; break; + case 0x2502: index = 0xb3; break; + case 0x2524: index = 0xb4; break; + case 0x2561: index = 0xb5; break; + case 0x2562: index = 0xb6; break; + case 0x2556: index = 0xb7; break; + case 0x2555: index = 0xb8; break; + case 0x2563: index = 0xb9; break; + case 0x2551: index = 0xba; break; + case 0x2557: index = 0xbb; break; + case 0x255d: index = 0xbc; break; + case 0x255c: index = 0xbd; break; + case 0x255b: index = 0xbe; break; + case 0x2510: index = 0xbf; break; + case 0x2514: index = 0xc0; break; + case 0x2534: index = 0xc1; break; + case 0x252c: index = 0xc2; break; + case 0x251c: index = 0xc3; break; + case 0x2500: index = 0xc4; break; + case 0x253c: index = 0xc5; break; + case 0x255e: index = 0xc6; break; + case 0x255f: index = 0xc7; break; + case 0x255a: index = 0xc8; break; + case 0x2554: index = 0xc9; break; + case 0x2569: index = 0xca; break; + case 0x2566: index = 0xcb; break; + case 0x2560: index = 0xcc; break; + case 0x2550: index = 0xcd; break; + case 0x256c: index = 0xce; break; + case 0x2567: index = 0xcf; break; + case 0x2568: index = 0xd0; break; + case 0x2564: index = 0xd1; break; + case 0x2565: index = 0xd2; break; + case 0x2559: index = 0xd3; break; + case 0x2558: index = 0xd4; break; + case 0x2552: index = 0xd5; break; + case 0x2553: index = 0xd6; break; + case 0x256b: index = 0xd7; break; + case 0x256a: index = 0xd8; break; + case 0x2518: index = 0xd9; break; + case 0x250c: index = 0xda; break; + case 0x2588: index = 0xdb; break; + case 0x2584: index = 0xdc; break; + case 0x258c: index = 0xdd; break; + case 0x2590: index = 0xde; break; + case 0x2580: index = 0xdf; break; + case 0x3b1: index = 0xe0; break; + case 0xdf: index = 0xe1; break; + case 0x393: index = 0xe2; break; + case 0x3c0: index = 0xe3; break; + case 0x3a3: index = 0xe4; break; + case 0x3c3: index = 0xe5; break; + case 0xb5: index = 0xe6; break; + case 0x3c4: index = 0xe7; break; + case 0x3a6: index = 0xe8; break; + case 0x398: index = 0xe9; break; + case 0x3a9: index = 0xea; break; + case 0x3b4: index = 0xeb; break; + case 0x221e: index = 0xec; break; + case 0x3c6: index = 0xed; break; + case 0x3b5: index = 0xee; break; + case 0x2229: index = 0xef; break; + case 0x2261: index = 0xf0; break; + case 0xb1: index = 0xf1; break; + case 0x2265: index = 0xf2; break; + case 0x2264: index = 0xf3; break; + case 0x2320: index = 0xf4; break; + case 0x2321: index = 0xf5; break; + case 0xf7: index = 0xf6; break; + case 0x2248: index = 0xf7; break; + case 0xb0: index = 0xf8; break; + case 0x2219: index = 0xf9; break; + case 0xb7: index = 0xfa; break; + case 0x221a: index = 0xfb; break; + case 0x207f: index = 0xfc; break; + case 0xb2: index = 0xfd; break; + case 0x25a0: index = 0xfe; break; + case 0xa0: index = 0xff; break; + default: + /* Non-CP437 character: use "unknown" glyph */ + index = VESAFB_UNKNOWN; + } } /* Copy glyph from BIOS font table */ @@ -443,34 +575,36 @@ static void vesafb_restore ( void ) { */ static int vesafb_init ( struct console_configuration *config ) { uint32_t discard_b; - uint16_t *mode_numbers; + uint16_t *mode_numbers = NULL; int mode_number; int rc; - /* Record current VGA mode */ - __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) - : "=a" ( vesafb.saved_mode ), "=b" ( discard_b ) - : "a" ( VBE_GET_VGA_MODE ) ); - DBGC ( &vbe_buf, "VESAFB saved VGA mode %#02x\n", vesafb.saved_mode ); - - /* Get VESA mode list */ - if ( ( rc = vesafb_mode_list ( &mode_numbers ) ) != 0 ) - goto err_mode_list; - - /* Select mode */ - if ( ( mode_number = vesafb_select_mode ( mode_numbers, config->width, - config->height, - config->depth ) ) < 0 ) { - rc = mode_number; - goto err_select_mode; - } + if ( ! config->lazy_update ) { + /* Record current VGA mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( vesafb.saved_mode ), "=b" ( discard_b ) + : "a" ( VBE_GET_VGA_MODE ) ); + DBGC ( &vbe_buf, "VESAFB saved VGA mode %#02x\n", vesafb.saved_mode ); + + /* Get VESA mode list */ + if ( ( rc = vesafb_mode_list ( &mode_numbers ) ) != 0 ) + goto err_mode_list; + + /* Select mode */ + if ( ( mode_number = vesafb_select_mode ( mode_numbers, config->width, + config->height, + config->depth ) ) < 0 ) { + rc = mode_number; + goto err_select_mode; + } - /* Set mode */ - if ( ( rc = vesafb_set_mode ( mode_number ) ) != 0 ) - goto err_set_mode; + /* Set mode */ + if ( ( rc = vesafb_set_mode ( mode_number ) ) != 0 ) + goto err_set_mode; - /* Get font data */ - vesafb_font(); + /* Get font data */ + vesafb_font(); + } /* Initialise frame buffer console */ if ( ( rc = fbcon_init ( &vesafb.fbcon, phys_to_user ( vesafb.start ), @@ -523,17 +657,38 @@ static void vesafb_putchar ( int character ) { static int vesafb_configure ( struct console_configuration *config ) { int rc; - /* Reset console, if applicable */ - if ( ! vesafb_console.disabled ) { - vesafb_fini(); - bios_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; - ansicol_reset_magic(); + if ( config && config->lazy_update ) { + if ( vesafb_console.disabled ) { + /* --update mode with disabled console -> nothing to do */ + return 0; + } + /* No width/height given, use current so we can update the border */ + if ( ( config->width == 0 ) || ( config->height == 0 ) ) { + if ( ( vesafb.pixel.width == 0 ) || ( vesafb.pixel.height == 0 ) ) { + return -EINVAL; + } + config->width = vesafb.pixel.width; + config->height = vesafb.pixel.height; + } else { + /* Otherwise make sure the new dimensions match the old ones */ + if ( ( vesafb.pixel.width != config->width ) || + ( vesafb.pixel.height != config->height ) ) { + return -EINVAL; + } + } + } else { + /* Reset console, if applicable */ + if ( ! vesafb_console.disabled ) { + vesafb_fini(); + bios_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; + ansicol_reset_magic(); + } + vesafb_console.disabled = CONSOLE_DISABLED; } - vesafb_console.disabled = CONSOLE_DISABLED; /* Do nothing more unless we have a usable configuration */ if ( ( config == NULL ) || - ( config->width == 0 ) || ( config->height == 0 ) ) { + ( config->width == 0 ) || ( config->height == 0 ) ) { return 0; } @@ -541,13 +696,15 @@ static int vesafb_configure ( struct console_configuration *config ) { if ( ( rc = vesafb_init ( config ) ) != 0 ) return rc; - /* Mark console as enabled */ - vesafb_console.disabled = 0; - bios_console.disabled |= CONSOLE_DISABLED_OUTPUT; + if ( ! config->lazy_update ) { + /* Mark console as enabled */ + vesafb_console.disabled = 0; + bios_console.disabled |= CONSOLE_DISABLED_OUTPUT; - /* Set magic colour to transparent if we have a background picture */ - if ( config->pixbuf ) - ansicol_set_magic_transparent(); + /* Set magic colour to transparent if we have a background picture */ + if ( config->pixbuf ) + ansicol_set_magic_transparent(); + } return 0; } diff --git a/src/config/config_efi.c b/src/config/config_efi.c index 92678d12..29bd14cb 100644 --- a/src/config/config_efi.c +++ b/src/config/config_efi.c @@ -49,3 +49,11 @@ REQUIRE_OBJECT ( efi_fbcon ); #ifdef DOWNLOAD_PROTO_FILE REQUIRE_OBJECT ( efi_local ); #endif + +/* + * Drag in EFI-specific commands + * + */ +#ifdef EFIMAP_CMD +REQUIRE_OBJECT ( efimap_cmd ); +#endif diff --git a/src/config/general.h b/src/config/general.h index e883e072..6525834e 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -168,6 +168,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define CERT_CMD /* Certificate management commands */ //#define IMAGE_MEM_CMD /* Read memory command */ #define IMAGE_ARCHIVE_CMD /* Archive image management commands */ +#define EFIMAP_CMD /* EFI Map command */ #define SHIM_CMD /* EFI shim command (or dummy command) */ /* diff --git a/src/core/fbcon.c b/src/core/fbcon.c index ff3132ac..056b164c 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -525,6 +525,9 @@ static int fbcon_picture_init ( struct fbcon *fbcon, /* Allocate buffer */ len = ( pixel->height * pixel->stride ); + if ( picture->start ) { + ufree( picture->start ); + } picture->start = umalloc ( len ); if ( ! picture->start ) { DBGC ( fbcon, "FBCON %p could not allocate %zd bytes for " @@ -600,21 +603,23 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, unsigned int bottom; int rc; - /* Initialise data structure */ - memset ( fbcon, 0, sizeof ( *fbcon ) ); - fbcon->start = start; - fbcon->pixel = pixel; - assert ( pixel->len <= sizeof ( uint32_t ) ); - fbcon->map = map; - fbcon->font = font; - fbcon->ctx.handlers = fbcon_ansiesc_handlers; - fbcon->show_cursor = 1; - - /* Derive overall length */ - fbcon->len = ( pixel->height * pixel->stride ); - DBGC ( fbcon, "FBCON %p at [%08lx,%08lx)\n", fbcon, - user_to_phys ( fbcon->start, 0 ), - user_to_phys ( fbcon->start, fbcon->len ) ); + if ( ! config->lazy_update ) { + /* Initialise data structure */ + memset ( fbcon, 0, sizeof ( *fbcon ) ); + fbcon->start = start; + fbcon->pixel = pixel; + assert ( pixel->len <= sizeof ( uint32_t ) ); + fbcon->map = map; + fbcon->font = font; + fbcon->ctx.handlers = fbcon_ansiesc_handlers; + fbcon->show_cursor = 1; + + /* Derive overall length */ + fbcon->len = ( pixel->height * pixel->stride ); + DBGC ( fbcon, "FBCON %p at [%08lx,%08lx)\n", fbcon, + user_to_phys ( fbcon->start, 0 ), + user_to_phys ( fbcon->start, fbcon->len ) ); + } /* Calculate margin. If the actual screen size is larger than * the requested screen size, then update the margins so that @@ -669,27 +674,32 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, fbcon->margin.top, ( fbcon->pixel->height - fbcon->margin.bottom ) ); - /* Set default colours */ - fbcon_set_default_foreground ( fbcon ); - fbcon_set_default_background ( fbcon ); + if ( ! config->lazy_update ) { + /* Set default colours */ + fbcon_set_default_foreground ( fbcon ); + fbcon_set_default_background ( fbcon ); + + /* Allocate and initialise stored character array */ + fbcon->text.start = umalloc ( fbcon->character.width * + fbcon->character.height * + sizeof ( struct fbcon_text_cell ) ); + if ( ! fbcon->text.start ) { + rc = -ENOMEM; + goto err_text; + } + fbcon_clear ( fbcon, 0 ); - /* Allocate and initialise stored character array */ - fbcon->text.start = umalloc ( fbcon->character.width * - fbcon->character.height * - sizeof ( struct fbcon_text_cell ) ); - if ( ! fbcon->text.start ) { - rc = -ENOMEM; - goto err_text; + /* Set framebuffer to all black (including margins) */ + memset_user ( fbcon->start, 0, 0, fbcon->len ); + } else { + fbcon_clear ( fbcon, 0 ); } - fbcon_clear ( fbcon, 0 ); - - /* Set framebuffer to all black (including margins) */ - memset_user ( fbcon->start, 0, 0, fbcon->len ); /* Generate pixel buffer from background image, if applicable */ if ( config->pixbuf && - ( ( rc = fbcon_picture_init ( fbcon, config->pixbuf ) ) != 0 ) ) - goto err_picture; + ( ( rc = fbcon_picture_init ( fbcon, config->pixbuf ) ) != 0 ) && + ( ! config->lazy_update ) ) + goto err_picture; /* Keep going w/o background in lazy_update mode */ /* Draw background picture (including margins), if applicable */ if ( fbcon->picture.start ) { diff --git a/src/core/menu.c b/src/core/menu.c index ab5b0c7f..abad5999 100644 --- a/src/core/menu.c +++ b/src/core/menu.c @@ -80,6 +80,7 @@ struct menu * create_menu ( const char *name, const char *title ) { strcpy ( title_copy, title ); menu->title = title_copy; INIT_LIST_HEAD ( &menu->items ); + INIT_LIST_HEAD ( &menu->hidden_items ); /* Add to list of menus */ list_add_tail ( &menu->list, &menus ); @@ -102,7 +103,7 @@ struct menu * create_menu ( const char *name, const char *title ) { */ struct menu_item * add_menu_item ( struct menu *menu, const char *label, const char *text, int shortcut, - int is_default ) { + int is_default, int is_hidden ) { size_t label_len; size_t text_len; size_t len; @@ -135,7 +136,11 @@ struct menu_item * add_menu_item ( struct menu *menu, const char *label, item->is_default = is_default; /* Add to list of items */ - list_add_tail ( &item->list, &menu->items ); + if ( is_hidden ) { + list_add_tail ( &item->list, &menu->hidden_items ); + } else { + list_add_tail ( &item->list, &menu->items ); + } return item; } @@ -157,6 +162,10 @@ void destroy_menu ( struct menu *menu ) { list_del ( &item->list ); free ( item ); } + list_for_each_entry_safe ( item, tmp, &menu->hidden_items, list ) { + list_del ( &item->list ); + free ( item ); + } /* Free menu */ free ( menu ); diff --git a/src/core/settings.c b/src/core/settings.c index 9fbf753a..aa4bbae2 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/init.h> #include <ipxe/version.h> #include <ipxe/settings.h> +#include <ipxe/md5.h> /** @file * @@ -2133,6 +2134,46 @@ static int format_hex_raw_setting ( const struct setting_type *type __unused, return hex_encode ( 0, raw, raw_len, buf, len ); } +/** + * Parsing md5 setting doesn't make any sense + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @v size Integer size, in bytes + * @ret len Length of raw value, or negative error + */ +static int parse_md5_setting ( const struct setting_type *type __unused, + const char *value __unused, void *buf __unused, + size_t len __unused ) { + return -ENOTSUP; +} + +/** + * Format setting value as md5 hash (hex representation) + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int format_md5_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, + char *buf, size_t len ) { + struct md5_context ctx; + uint8_t digest[MD5_DIGEST_SIZE]; + + if ( len < MD5_DIGEST_SIZE * 2 ) + return MD5_DIGEST_SIZE * 2; + digest_init ( &md5_algorithm, &ctx ); + digest_update ( &md5_algorithm, &ctx, raw, raw_len ); + digest_final ( &md5_algorithm, &ctx, digest ); + return hex_encode ( 0, digest, sizeof(digest), buf, len ); +} + /** A hex-string setting (colon-delimited) */ const struct setting_type setting_type_hex __setting_type = { .name = "hex", @@ -2154,6 +2195,12 @@ const struct setting_type setting_type_hexraw __setting_type = { .format = format_hex_raw_setting, }; +const struct setting_type setting_type_md5 __setting_type = { + .name = "md5", + .parse = parse_md5_setting, + .format = format_md5_setting, +}; + /** * Parse Base64-encoded setting value * diff --git a/src/drivers/net/marvell/aqc1xx.c b/src/drivers/net/marvell/aqc1xx.c new file mode 100644 index 00000000..42b8164a --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.c @@ -0,0 +1,643 @@ +/** @file + * + * Marvell AQtion family network card driver. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +FILE_LICENCE ( BSD2 ); + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/iobuf.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include <ipxe/profile.h> + +#include "aqc1xx.h" + +extern struct atl_hw_ops atl_hw; +extern struct atl_hw_ops atl2_hw; + +/** @file +* +* Marvell AQC network card driver +* +*/ + +static int atl_ring_alloc ( const struct atl_nic *nic, struct atl_ring *ring, + uint32_t desc_size, uint32_t reg_base ) +{ + physaddr_t phy_addr; + + /* Allocate ring buffer.*/ + ring->length = ATL_RING_SIZE * desc_size; + ring->ring = dma_alloc ( nic->dma, &ring->map, ring->length, + ring->length ); + + if ( !ring->ring ) + return -ENOMEM; + + /* Initialize the descriptor ring */ + memset ( ring->ring, 0, ring->length ); + + /* Program ring address */ + phy_addr = dma ( &ring->map, ring->ring ); + + /* Write ring address (hi & low parts).*/ + ATL_WRITE_REG ( (uint32_t)phy_addr, reg_base ); + ATL_WRITE_REG ( (uint32_t)(((uint64_t)phy_addr) >> 32), reg_base + 4 ); + + /* Write ring length.*/ + ATL_WRITE_REG ( ATL_RING_SIZE, reg_base + 8 ); + + ring->sw_head = ring->sw_tail = 0; + + DBGC ( nic, "AQUANTIA: %p ring is at [%08llx,%08llx), reg base %#x\n", + nic, ((unsigned long long)phy_addr), + ((unsigned long long) phy_addr + ring->length), reg_base ); + + return 0; +} + +static void atl_ring_free ( struct atl_ring *ring ) +{ + dma_free ( &ring->map, ring->ring, ring->length ); + ring->ring = NULL; + ring->length = 0; +} + +static void atl_ring_next_dx ( unsigned int *val ) +{ + ++( *val ); + if ( *val == ATL_RING_SIZE ) + *val = 0; +} + +int atl_ring_full ( const struct atl_ring *ring ) +{ + unsigned int tail = ring->sw_tail; + atl_ring_next_dx ( &tail ); + return tail == ring->sw_head; +} + +void atl_rx_ring_fill ( struct atl_nic *nic ) +{ + struct atl_desc_rx *rx; + struct io_buffer *iobuf; + physaddr_t address; + unsigned int refilled = 0; + + /* Refill ring */ + while ( !atl_ring_full ( &nic->rx_ring ) ) { + + /* Allocate I/O buffer */ + iobuf = alloc_rx_iob ( ATL_RX_MAX_LEN, nic->dma ); + if ( !iobuf ) { + /* Wait for next refill */ + break; + } + + /* Get next receive descriptor */ + rx = ( struct atl_desc_rx * )nic->rx_ring.ring + + nic->rx_ring.sw_tail; + + /* Populate receive descriptor */ + address = iob_dma ( iobuf ); + rx->data_addr = address; + rx->hdr_addr = 0; + + /* Record I/O buffer */ + assert ( nic->iobufs[nic->rx_ring.sw_tail] == NULL ); + nic->iobufs[nic->rx_ring.sw_tail] = iobuf; + + DBGC( nic, "AQUANTIA: RX[%d] is [%llx,%llx)\n", + nic->rx_ring.sw_tail, + ( (unsigned long long)address), + ( (unsigned long long)address + ATL_RX_MAX_LEN) ); + + atl_ring_next_dx ( &nic->rx_ring.sw_tail ); + refilled++; + } + + /* Push descriptors to card, if applicable */ + if ( refilled ) { + wmb(); + ATL_WRITE_REG ( nic->rx_ring.sw_tail, ATL_RING_TAIL_PTR ); + } +} + +/** +* Open network device +* +* @v netdev Network device +* @ret rc Return status code +*/ +static int atl_open ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t ctrl = 0; + + /* Tx ring */ + if ( atl_ring_alloc ( nic, &nic->tx_ring, sizeof(struct atl_desc_tx), + ATL_TX_DMA_DESC_ADDR ) != 0 ) + goto err_tx_alloc; + + /* Rx ring */ + if ( atl_ring_alloc ( nic, &nic->rx_ring, sizeof(struct atl_desc_rx), + ATL_RX_DMA_DESC_ADDR ) != 0 ) + goto err_rx_alloc; + + /* Allocate interrupt vectors */ + ATL_WRITE_REG ( (ATL_IRQ_CTRL_COR_EN | ATL_IRQ_CTRL_REG_RST_DIS), + ATL_IRQ_CTRL ); + + /*TX & RX Interruprt Mapping*/ + ctrl = ATL_IRQ_MAP_REG1_RX0 | ATL_IRQ_MAP_REG1_RX0_EN | + ATL_IRQ_MAP_REG1_TX0 | ATL_IRQ_MAP_REG1_TX0_EN; + ATL_WRITE_REG ( ctrl, ATL_IRQ_MAP_REG1 ); + + /*TX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_TX_IRQ_CTRL_WB_EN, ATL_TX_IRQ_CTRL ); + + /*RX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_RX_IRQ_CTRL_WB_EN, ATL_RX_IRQ_CTRL ); + + /*RX data path*/ + ctrl = ATL_IRQ_TX | ATL_IRQ_RX; + /* itr mask */ + ATL_WRITE_REG ( ctrl, ATL_ITR_MSKS ); + ATL_WRITE_REG ( (uint32_t)ATL_RX_MAX_LEN / 1024U, + ATL_RX_DMA_DESC_BUF_SIZE ); + + /*filter global ctrl */ + ctrl = ATL_RPF_CTRL1_BRC_EN | ATL_RPF_CTRL1_L2_PROMISC | + ATL_RPF_CTRL1_ACTION | ATL_RPF_CTRL1_BRC_TSH; + ATL_WRITE_REG ( ctrl, ATL_RPF_CTRL1 ); + + /* vlan promisc */ + ATL_WRITE_REG ( ATL_RPF_CTRL2_VLAN_PROMISC, ATL_RPF_CTRL2 ); + /* enable rpf2 */ + ATL_WRITE_REG ( ATL_RPF2_CTRL_EN, ATL_RPF2_CTRL ); + + /* RX Packet Buffer 0 Register 1 */ + ATL_WRITE_REG ( ATL_RPB0_CTRL1_SIZE, ATL_RPB0_CTRL1 ); + + /*RX Packet Buffer 0 Register 2 */ + ctrl = ATL_RPB0_CTRL2_LOW_TSH | ATL_RPB0_CTRL2_HIGH_TSH | + ATL_RPB0_CTRL2_FC_EN; + ATL_WRITE_REG ( ctrl, ATL_RPB0_CTRL2 ); + + /*RPB global ctrl*/ + ctrl = ATL_READ_REG(ATL_RPB_CTRL); + ctrl |= (ATL_RPB_CTRL_EN | ATL_RPB_CTRL_FC); + ATL_WRITE_REG ( ctrl, ATL_RPB_CTRL ); + + /*TX data path*/ + /* enable tpo2 */ + ATL_WRITE_REG ( ATL_TPO2_EN, ATL_TPO2_CTRL ); + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ATL_TPB0_CTRL1_SIZE, ATL_TPB0_CTRL1 ); + + ctrl = ATL_TPB0_CTRL2_LOW_TSH | ATL_TPB0_CTRL2_HIGH_TSH; + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ctrl, ATL_TPB0_CTRL2 ); + + ctrl = ATL_READ_REG ( ATL_TPB_CTRL ); + ctrl |= ( ATL_TPB_CTRL_EN | ATL_TPB_CTRL_PAD_EN ); + /* tpb global ctrl */ + ATL_WRITE_REG ( ctrl, ATL_TPB_CTRL ); + + /*Enable rings*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_TX_CTRL ) | ATL_RING_TX_CTRL_EN, + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_RX_CTRL ) | ATL_RING_RX_CTRL_EN, + ATL_RING_RX_CTRL ); + + if ( nic->flags == ATL_FLAG_A2 ) { + ATL_WRITE_REG ( ATL2_RPF_NEW_EN_ADR_EN, ATL2_RPF_NEW_EN_ADR ); + } + + atl_rx_ring_fill ( nic ); + + nic->hw_ops->start ( nic ); + + return 0; + +err_rx_alloc: + atl_ring_free ( &nic->tx_ring ); + +err_tx_alloc: + return -ENOMEM; +} + +/** +* Close network device +* +* @v netdev Network device +*/ +static void atl_close ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + + nic->hw_ops->stop ( nic ); + /* rpb global ctrl */ + ATL_WRITE_REG ( ATL_RPB_CTRL_DIS, ATL_RPB_CTRL ); + /* tgb global ctrl */ + ATL_WRITE_REG ( ATL_TPB_CTRL_DIS, ATL_TPB_CTRL); + + ATL_WRITE_REG ( ATL_READ_REG(ATL_RING_TX_CTRL) | (~ATL_RING_TX_CTRL_EN), + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_RING_RX_CTRL) | (~ATL_RING_RX_CTRL_EN), + ATL_RING_RX_CTRL ); + + /* clear itr mask */ + ATL_WRITE_REG ( ATL_ITR_MSKS_DIS, ATL_ITR_MSKS ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + atl_ring_free ( &nic->tx_ring ); + atl_ring_free ( &nic->rx_ring ); +} + +/** +* Transmit packet +* +* @v netdev Network device +* @v iobuf I/O buffer +* @ret rc Return status code +*/ +int atl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx *tx; + physaddr_t address; + uint32_t len; + + /* Get next transmit descriptor */ + if ( atl_ring_full ( &nic->tx_ring ) ) { + DBGC ( nic, "AQUANTIA: %p out of transmit descriptors\n", nic ); + return -ENOBUFS; + } + + tx = (struct atl_desc_tx *)nic->tx_ring.ring + nic->tx_ring.sw_tail; + + /* Populate transmit descriptor */ + memset ( tx, 0, sizeof ( *tx ) ); + address = iob_dma ( iobuf ); + tx->address = address; + len = iob_len ( iobuf ); + + tx->status = 0x1; + tx->status = ( (tx->status) & ~ATL_DESC_TX_BUF_LEN_MASK) | + ((len << ATL_DESC_TX_BUF_LEN_OFFSET) & + ATL_DESC_TX_BUF_LEN_MASK ); + tx->status = ((tx->status) & ~ATL_DESC_TX_EOP_MASK) | + ( (ATL_DESC_TX_DX_EOP_VALUE << ATL_DESC_TX_EOP_OFFSET) & + ATL_DESC_TX_EOP_MASK ); + tx->status = ( (tx->status) & ~ATL_DESC_TX_CMD_MASK) | + ((ATL_DESC_TX_CMD_VALUE << ATL_DESC_TX_CMD_OFFSET) & + ATL_DESC_TX_CMD_MASK ); + tx->flag = ( (tx->flag) & ~ATL_DESC_TX_PAY_LEN_MASK) | + ((len << ATL_DESC_TX_PAY_LEN_OFFSET) & + ATL_DESC_TX_PAY_LEN_MASK ); + wmb(); + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] is [%llx, %llx]\n", + nic, nic->tx_ring.sw_tail, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + atl_ring_next_dx ( &nic->tx_ring.sw_tail ); + ATL_WRITE_REG ( nic->tx_ring.sw_tail, ATL_RING_TAIL ); + + return 0; +} + +void atl_check_link ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t link_state; + + /* Read link status */ + link_state = nic->hw_ops->get_link ( nic ); + + DBGC ( nic, "AQUANTIA: %p link status is %08x\n", nic, link_state ); + + if ( link_state != nic->link_state ) { + if ( link_state ) { + DBGC ( nic, "AQUANTIA: link up\n"); + netdev_link_up ( netdev ); + } else { + DBGC ( nic, "AQUANTIA: link lost\n"); + netdev_link_down ( netdev ); + } + nic->link_state = link_state; + } +} + +/** +* Poll for completed packets +* +* @v netdev Network device +*/ +void atl_poll_tx ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx_wb *tx; + + /* Check for completed packets */ + while ( nic->tx_ring.sw_head != nic->tx_ring.sw_tail ) { + + /* Get next transmit descriptor */ + tx = ( struct atl_desc_tx_wb * )nic->tx_ring.ring + + nic->tx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !(tx->status & cpu_to_le32 ( ATL_TX_DESC_STATUS_DD ) ) ) + return; + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] complete\n", + nic, nic->tx_ring.sw_head ); + + /* Complete TX descriptor */ + atl_ring_next_dx ( &nic->tx_ring.sw_head ); + netdev_tx_complete_next ( netdev ); + } +} + +/** +* Poll for received packets +* +* @v netdev Network device +*/ +void atl_poll_rx ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_rx_wb *rx; + struct io_buffer *iobuf; + size_t len; + + /* Check for received packets */ + while ( nic->rx_ring.sw_head != nic->rx_ring.sw_tail ) { + + /* Get next receive descriptor */ + rx = (struct atl_desc_rx_wb *)nic->rx_ring.ring + + nic->rx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !(rx->status & cpu_to_le16(ATL_RX_DESC_STATUS_DD)) ) + return; + + /* Populate I/O buffer */ + iobuf = nic->iobufs[nic->rx_ring.sw_head]; + nic->iobufs[nic->rx_ring.sw_head] = NULL; + len = le16_to_cpu ( rx->pkt_len ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + DBGC ( nic, "AQUANTIA: %p RX[%d] complete (length %zd)\n", + nic, nic->rx_ring.sw_head, len ); + + netdev_rx ( netdev, iobuf ); + + atl_ring_next_dx ( &nic->rx_ring.sw_head ); + } +} + +/** +* Poll for completed and received packets +* +* @v netdev Network device +*/ +static void atl_poll ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + + /* Check link state */ + atl_check_link ( netdev ); + + /* Poll for TX completions */ + atl_poll_tx ( netdev ); + + /* Poll for RX completions */ + atl_poll_rx ( netdev ); + + /* Refill RX ring */ + atl_rx_ring_fill ( nic ); +} + +/** +* Enable or disable interrupts +* +* @v netdev Network device +* @v enable Interrupts should be enabled +*/ +static void atl_irq ( struct net_device *netdev, int enable ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t mask; + + mask = ( ATL_IRQ_TX | ATL_IRQ_RX ); + if ( enable ) + ATL_WRITE_REG ( mask, ATL_ITR_MSKS ); + else + ATL_WRITE_REG ( mask, ATL_ITR_MSKC ); +} + +/** Marvell network device operations */ +static struct net_device_operations atl_operations = { + .open = atl_open, + .close = atl_close, + .transmit = atl_transmit, + .poll = atl_poll, + .irq = atl_irq, +}; + +/****************************************************************************** +* +* PCI interface +* +******************************************************************************* +*/ + +/** +* Probe PCI device +* +* @v pci PCI device +* @ret rc Return status code +*/ +static int atl_probe ( struct pci_device *pci ) +{ + struct net_device *netdev; + struct atl_nic *nic; + int rc = ENOERR; + uint32_t io_size = 0; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof( *nic ) ); + if ( !netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &atl_operations ); + nic = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset( nic, 0, sizeof( *nic ) ); + nic->flags = pci->id->driver_data; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + switch ( nic->flags ) { + case ATL_FLAG_A1: + nic->hw_ops = &atl_hw; + io_size = ATL_BAR_SIZE; + break; + case ATL_FLAG_A2: + nic->hw_ops = &atl2_hw; + io_size = ATL2_BAR_SIZE; + break; + default: + goto err_unsupported; + break; + } + + /* Map registers */ + nic->regs = pci_ioremap ( pci, pci->membase, io_size ); + if ( !nic->regs ) { + rc = -ENODEV; + goto err_ioremap; + } + + /* Configure DMA */ + nic->dma = &pci->dma; + + /* Reset the NIC */ + if ( ( rc = nic->hw_ops->reset ( nic ) ) != 0 ) + goto err_reset; + + /* Get MAC Address */ + if ( ( rc = nic->hw_ops->get_mac ( nic, netdev->hw_addr ) ) != 0 ) + goto err_mac; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + netdev_link_down ( netdev ); + + return 0; + +err_register_netdev: +err_mac: + nic->hw_ops->reset ( nic ); +err_reset: + iounmap ( nic->regs ); +err_ioremap: + netdev_nullify ( netdev ); + netdev_put ( netdev ); +err_unsupported: +err_alloc: + return rc; +} + +/** +* Remove PCI device +* +* @v pci PCI device +*/ +static void atl_remove ( struct pci_device *pci ) +{ + struct net_device *netdev = pci_get_drvdata ( pci ); + struct atl_nic *nic = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + /* Free network device */ + iounmap ( nic->regs ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Marvell PCI device IDs */ +static struct pci_device_id atl_nics[] = { + /* Atlantic 1 */ + /* 10G */ + PCI_ROM(0x1D6A, 0x0001, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0xD107, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x07B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x87B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + + /* SFP */ + PCI_ROM(0x1D6A, 0xD100, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x00B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x80B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + + /* 5G */ + PCI_ROM(0x1D6A, 0xD108, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x08B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x88B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x11B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x91B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + + /* 2.5G */ + PCI_ROM(0x1D6A, 0xD109, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x09B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x89B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x12B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x92B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + + /* Atlantic 2 */ + PCI_ROM(0x1D6A, 0x00C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x94C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x93C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x04C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x14C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x12C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), +}; + +/** Marvell PCI driver */ +struct pci_driver atl_driver __pci_driver = { + .ids = atl_nics, + .id_count = (sizeof(atl_nics) / sizeof(atl_nics[0])), + .probe = atl_probe, + .remove = atl_remove, +};
\ No newline at end of file diff --git a/src/drivers/net/marvell/aqc1xx.h b/src/drivers/net/marvell/aqc1xx.h new file mode 100644 index 00000000..c3e34e1e --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.h @@ -0,0 +1,270 @@ +/** @file + * + * Marvell AQtion family network card driver definitions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ATLANTIC_H +#define _ATLANTIC_H + +FILE_LICENCE ( BSD2 ); + +#include <stdint.h> +#include <ipxe/if_ether.h> +#include <ipxe/nvs.h> + +#define ATL_BAR_SIZE 0x10000 +#define ATL2_BAR_SIZE 0x40000 +#define ATL_RING_SIZE 64 +#define ATL_RING_ALIGN 128 +#define ATL_RX_MAX_LEN 2048 + +#define ATL_IRQ_TX 0x00000001U +#define ATL_IRQ_RX 0x00000002U + +/*IRQ Status Register*/ +#define ATL_IRQ_STAT_REG 0x00002000U + +/* Interrupt Vector Allocation Register */ +#define ATL_IRQ_CTRL 0x00002300U +#define ATL_IRQ_CTRL_COR_EN 0x00000080U /*IRQ clear on read */ +#define ATL_IRQ_CTRL_REG_RST_DIS 0x20000000U /*Register reset disable */ + +/*TX/RX Interruprt Mapping*/ +#define ATL_IRQ_MAP_REG1 0x00002100U /*IRQ mapping register */ + +#define ATL_IRQ_MAP_REG1_RX0_EN 0x00008000U /*IRQ RX0 enable*/ +#define ATL_IRQ_MAP_REG1_RX0 0x00000100U /*IRQ RX0*/ + +#define ATL_IRQ_MAP_REG1_TX0_EN 0x80000000U /*IRQ TX0 enable*/ +#define ATL_IRQ_MAP_REG1_TX0 0x00000000U /*IRQ TX0*/ + +/*TX interrupt ctrl reg*/ +#define ATL_TX_IRQ_CTRL 0x00007B40U +#define ATL_TX_IRQ_CTRL_WB_EN 0x00000002U + +/*RX interrupt ctrl reg*/ +#define ATL_RX_IRQ_CTRL 0x00005A30U +#define ATL_RX_IRQ_CTRL_WB_EN 0x00000004U + +#define ATL_GLB_CTRL 0x00000000U + +#define ATL_PCI_CTRL 0x00001000U +#define ATL_PCI_CTRL_RST_DIS 0x20000000U + +#define ATL_RX_CTRL 0x00005000U +#define ATL_RX_CTRL_RST_DIS 0x20000000U /*RPB reset disable */ +#define ATL_TX_CTRL 0x00007000U +#define ATL_TX_CTRL_RST_DIS 0x20000000U /*TPB reset disable */ + +/*RX data path control registers*/ +#define ATL_RPF2_CTRL 0x00005040U +#define ATL_RPF2_CTRL_EN 0x000F0000U /* RPF2 enable*/ +#define ATL2_RPF_NEW_EN_ADR_EN 0x00000001U /*enable*/ +#define ATL2_RPF_NEW_EN_ADR 0x5104 + +#define ATL_RPF_CTRL1 0x00005100U +#define ATL_RPF_CTRL1_BRC_EN 0x00000001U /*Allow broadcast receive*/ +#define ATL_RPF_CTRL1_L2_PROMISC 0x00000008U /*L2 promiscious*/ +#define ATL_RPF_CTRL1_ACTION 0x00001000U /*Action to host*/ +#define ATL_RPF_CTRL1_BRC_TSH 0x00010000U /*Brc threshold 256 units per sec*/ + +#define ATL_RPF_CTRL2 0x00005280U +#define ATL_RPF_CTRL2_VLAN_PROMISC 0x00000002U /*VLAN promisc*/ + +#define ATL_RPB_CTRL_DIS 0x0 +#define ATL_RPB_CTRL 0x00005700U +#define ATL_RPB_CTRL_EN 0x00000001U /*RPB Enable*/ +#define ATL_RPB_CTRL_FC 0x00000010U /*RPB Enable*/ +#define ATL_RPB_CTRL_TC_MODE 0x00000100U /*RPB Traffic Class Mode*/ + +#define ATL_RPB0_CTRL1 0x00005710U +#define ATL_RPB0_CTRL1_SIZE 0x00000140U /*RPB size (in unit 1KB) \*/ + +#define ATL_RPB0_CTRL2 0x00005714U + +/*Buffer Low Threshold (70% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_LOW_TSH 0x00000C00U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_HIGH_TSH 0x1C000000U +#define ATL_RPB0_CTRL2_FC_EN 0x80000000U /*Flow control Enable*/ + +#define ATL_RX_DMA_DESC_BUF_SIZE 0x00005b18U +#define ATL_RX_DMA_DESC_ADDR 0x00005b00U + +/*TX data path control registers*/ +#define ATL_TPO2_CTRL 0x00007040U +#define ATL_TPO2_EN 0x00010000U /*TPO2 Enable*/ + +#define ATL_TPB_CTRL_DIS 0x0 +#define ATL_TPB_CTRL 0x00007900U +#define ATL_TPB_CTRL_EN 0x00000001U /*TPB enable*/ +#define ATL_TPB_CTRL_PAD_EN 0x00000004U /*Tx pad insert enable*/ +#define ATL_TPB_CTRL_TC_MODE 0x00000100U /*Tx traffic Class Mode*/ + +#define ATL_TPB0_CTRL1 0x00007910U +#define ATL_TPB0_CTRL1_SIZE 0x000000A0U /*TPB Size (in unit 1KB)*/ + +#define ATL_TPB0_CTRL2 0x00007914U +/*Buffer Low Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_LOW_TSH 0x00000600U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_HIGH_TSH 0x0E000000U + +#define ATL_TX_DMA_DESC_ADDR 0x00007c00U + +/*Rings control registers*/ +#define ATL_RING_TX_CTRL 0x00007c08U +#define ATL_RING_TX_CTRL_EN 0x80000000U /*Tx descriptor Enable*/ + +#define ATL_RING_RX_CTRL 0x00005b08U +#define ATL_RING_RX_CTRL_EN 0x80000000U /*Rx descriptor Enable*/ + +#define ATL_RING_TAIL 0x00007c10U +#define ATL_RING_TAIL_PTR 0x00005b10U + +/*IRQ control registers*/ +#define ATL_ITR_MSKS_DIS 0x0 +#define ATL_ITR_MSKS 0x00002060U +#define ATL_ITR_MSKS_LSW 0x0000000CU +#define ATL_ITR_MSKC 0x00002070U +#define ATL_ITR_MSKC_LSW 0x0000000CU + +/*Link advertising*/ +#define ATL_LINK_ADV 0x00000368U +#define ATL_SHUT_LINK 0x0 +#define ATL_LINK_ADV_AUTONEG 0xF20U + +#define ATL_LINK_ST 0x00000370U + +/*Semaphores*/ +#define ATL_SEM_RAM 0x000003a8U +#define ATL_SEM_RAM_RESET 0X1 + +/*Mailbox*/ +#define ATL_MBOX_ADDR 0x00000360U +#define ATL_MBOX_CTRL1 0x00000200U +#define ATL_MBOX_CTRL1_START_MBOX_OPT 0x8000 + +#define ATL_MBOX_CTRL3 0x00000208U +#define ATL_MBOX_CTRL5 0x0000020cU + +#define ATL_FLAG_A1 0x1 +#define ATL_FLAG_A2 0x2 + +/*write register*/ +#define ATL_WRITE_REG(VAL, REG) writel(VAL, nic->regs + (REG)) +#define ATL_READ_REG(REG) readl(nic->regs + (REG)) /*read register*/ + +struct atl_desc_tx { + uint64_t address; + uint32_t status; + uint32_t flag; +} __attribute__((packed)); + +#define ATL_DESC_TX_DX_TYPE_VALUE 0x1 + +#define ATL_DESC_TX_DX_EOP_VALUE 0x1 +#define ATL_DESC_TX_EOP_MASK 0x00200000 +#define ATL_DESC_TX_EOP_OFFSET 21 + +#define ATL_DESC_TX_CMD_MASK 0x3FC00000UL +#define ATL_DESC_TX_CMD_OFFSET 22 +#define ATL_DESC_TX_CMD_VALUE 0x22 + +#define ATL_DESC_TX_BUF_LEN_MASK 0x000FFFF0 +#define ATL_DESC_TX_BUF_LEN_OFFSET 5 + +#define ATL_DESC_TX_PAY_LEN_MASK 0xFFFFC000 +#define ATL_DESC_TX_PAY_LEN_OFFSET 14 + +struct atl_desc_tx_wb { + uint64_t rsvd1; + uint32_t status; + uint32_t rsvd4; +} __attribute__((packed)); + +#define ATL_TX_DESC_STATUS_DD 0x00100000UL + +struct atl_desc_rx { + uint64_t data_addr; + uint64_t hdr_addr; + +} __attribute__((packed)); + +struct atl_desc_rx_wb { + uint64_t rsvd2; + uint16_t status; + uint16_t pkt_len; + uint32_t rsvd4; +} __attribute__((packed)); + +#define ATL_RX_DESC_STATUS_DD 0x0001UL +#define ATL_RX_DESC_STATUS_EOP 0x0002UL +struct atl_ring { + unsigned int sw_tail; + unsigned int sw_head; + void *ring; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; + unsigned int length; +}; + +struct atl_nic; + +struct atl_hw_ops { + int (*reset) (struct atl_nic *nic); + int (*start) (struct atl_nic *nic); + int (*stop) (struct atl_nic *nic); + int (*get_link) (struct atl_nic *nic); + int (*get_mac) (struct atl_nic *, uint8_t *mac); +}; + +/** An aQuanita network card */ +struct atl_nic { + /** Registers */ + void *regs; + /** Port number (for multi-port devices) */ + unsigned int port; + /** DMA device */ + struct dma_device *dma; + /** Flags */ + unsigned int flags; + struct atl_ring tx_ring; + struct atl_ring rx_ring; + struct io_buffer *iobufs[ATL_RING_SIZE]; + uint32_t link_state; + uint32_t mbox_addr; + struct atl_hw_ops *hw_ops; +}; + +struct atl_hw_stats { + uint32_t version; + uint32_t tid; +}; + +#endif /* _AQUANTIA_H */ diff --git a/src/drivers/net/marvell/atl2_hw.c b/src/drivers/net/marvell/atl2_hw.c new file mode 100644 index 00000000..0c57a12f --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.c @@ -0,0 +1,235 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <ipxe/pci.h> +#include "aqc1xx.h" +#include "atl2_hw.h" + +static int atl2_hw_boot_completed_ ( struct atl_nic *nic ) +{ + uint32_t reset_status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + return ( reset_status & ATL2_RESET_STATUS_BOOT_COMPLETED_MASK ) || + ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ); +} + +void atl2_hw_read_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) +{ + uint32_t i; + + for (i = 0; i < len; ++i ) + { + data[i] = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +void atl2_hw_write_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) +{ + uint32_t i; + + for ( i = 0; i < len; ++i ) + { + ATL_WRITE_REG ( data[i], ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +int atl2_hw_finish_ack_ ( struct atl_nic *nic, uint32_t ms ) +{ + uint32_t i; + int err = 0; + + ATL_WRITE_REG ( ATL_READ_REG(ATL2_HOST_FINISHED_WRITE ) + | 1, ATL2_HOST_FINISHED_WRITE ); + + for ( i = 0; i < (ms / 100); ++i ) + { + if ( ( ATL_READ_REG(ATL2_MCP_BUSY_WRITE ) & 1 ) == 0 ) + { + break; + } + udelay ( ATL2_DELAY_100 ); + } + if (i == ( ms / 100 ) ) + err = -ETIME; + + return err; +} + +int atl2_hw_fw_init_ ( struct atl_nic *nic ) +{ + uint32_t val; + int err = 0; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + val |= ( ATL2_HOST_MODE_ACTIVE | ( 1U << 13 ) ); + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + val = 16352; + atl2_hw_write_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + err = atl2_hw_finish_ack_ ( nic, 50000000 ); + + return err; +} + +int atl2_hw_reset ( struct atl_nic *nic ) +{ + int completed = 0; + uint32_t status = 0; + uint32_t request; + int err = 0; + int i; + + request = ATL2_RESET_STATUS_REQ_GSR; + + ATL_WRITE_REG ( request, ATL2_GLB_RST_CTRL2 ); + + /* Wait for boot code started every 10us, 200 ms */ + for ( i = 0; i < 20000; ++i ) + { + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( ( ( status & ATL2_RESET_STATUS_BC_STARTED ) && + (status != 0xFFFFFFFFu ) ) ) + break; + + udelay ( ATL2_DELAY_10 ); + } + if ( i == 20000 ) + { + DBGC ( nic, "Boot code hanged" ); + err = -EIO; + goto err_exit; + } + + /* Wait for boot succeed, failed or host request every 10us, 480ms */ + for ( i = 0; i < 48000; ++i ) + { + completed = atl2_hw_boot_completed_ ( nic ); + if ( completed ) + break; + + udelay ( ATL2_DELAY_10 ); + } + + if ( !completed ) + { + DBGC ( nic, "FW Restart timed out" ); + err = -ETIME; + goto err_exit; + } + + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( status & ATL2_RESET_STATUS_BOOT_FAILED_MASK ) + { + err = -EIO; + DBGC ( nic, "FW Restart failed" ); + DBGC ( nic, "status = 0x%x", status ); + goto err_exit; + } + + if ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ) + { + err = -ENOTSUP; + DBGC ( nic, "Dynamic FW load not implemented" ); + goto err_exit; + } + + err = atl2_hw_fw_init_ ( nic ); + +err_exit: + return err; +} + +int atl2_hw_start ( struct atl_nic *nic ) +{ + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0x4B00FFE1; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000); +} + +int atl2_hw_stop ( struct atl_nic *nic ) +{ + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000 ); +} + +int atl2_hw_get_link ( struct atl_nic *nic ) +{ + uint32_t val; + + val = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_OUT + ATL2_LINK_STS_OUT_OFF ); + + return ( (val & 0xf) != 0) && ((val & 0xF0) != 0 ); +} + +int atl2_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) +{ + uint32_t mac_addr[2] = {0}; + + atl2_hw_read_shared_in_ ( nic, ATL2_MAC_ADDR_IN_OFF, mac_addr, 2 ); + + memcpy ( mac, (uint8_t *)mac_addr, 6 ); + + return 0; +} + +struct atl_hw_ops atl2_hw = { + .reset = atl2_hw_reset, + .start = atl2_hw_start, + .stop = atl2_hw_stop, + .get_link = atl2_hw_get_link, + .get_mac = atl2_hw_get_mac, +};
\ No newline at end of file diff --git a/src/drivers/net/marvell/atl2_hw.h b/src/drivers/net/marvell/atl2_hw.h new file mode 100644 index 00000000..ebd5466e --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.h @@ -0,0 +1,94 @@ +/* + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ATL2_HW_H +#define __ATL2_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL2_GLB_RST_CTRL2 0x3040 +#define ATL2_HOST_FINISHED_WRITE 0xE00 +#define ATL2_MCP_BUSY_WRITE 0xE04 +#define ATL2_HOST_ITR_REQ 0xF00 + + +#define ATL2_RESET_STATUS_REQ_GSR (1U << 0x0) +#define ATL2_RESET_STATUS_REQ_HOST_BOOT (1U << 0x8) +#define ATL2_RESET_STATUS_REQ_MAC_FAST_BOOT (1U << 0xA) +#define ATL2_RESET_STATUS_REQ_PHY_FAST_BOOT (1U << 0xB) + +#define ATL2_RESET_STATUS_HOST_LOAD_COMPLETED (1U << 0x10) +#define ATL2_RESET_STATUS_REQUIRE_HOST_LOAD (1U << 0x11) +#define ATL2_RESET_STATUS_BC_STARTED (1U << 0x18) +#define ATL2_RESET_STATUS_CRASH_DURING_INIT (1U << 0x1B) +#define ATL2_RESET_STATUS_BC_FAILED (1U << 0x1C) +#define ATL2_RESET_STATUS_FW_FAILED (1U << 0x1D) +#define ATL2_RESET_STATUS_FW_SUCCEED (1U << 0x1F) + +#define ATL2_RESET_STATUS_BOOT_FAILED_MASK (ATL2_RESET_STATUS_CRASH_DURING_INIT | ATL2_RESET_STATUS_BC_FAILED | ATL2_RESET_STATUS_FW_FAILED) +#define ATL2_RESET_STATUS_BOOT_COMPLETED_MASK (ATL2_RESET_STATUS_BOOT_FAILED_MASK | ATL2_RESET_STATUS_FW_SUCCEED) + +#define ATL2_FW_HOST_INTERRUPT_REQUEST_READY 0x0001 +#define ATL2_FW_HOST_INTERRUPT_MAC_READY 0x0004 +#define ATL2_FW_HOST_INTERRUPT_DATA_HANDLED 0x0100 +#define ATL2_FW_HOST_INTERRUPT_LINK_UP 0x0200 +#define ATL2_FW_HOST_INTERRUPT_LINK_DOWN 0x0400 +#define ATL2_FW_HOST_INTERRUPT_PHY_FAULT 0x0800 +#define ATL2_FW_HOST_INTERRUPT_MAC_FAULT 0x1000 +#define ATL2_FW_HOST_INTERRUPT_TEMPERATURE_WARNING 0x2000 +#define ATL2_FW_HOST_INTERRUPT_HEARTBEAT 0x4000 + +#define ATL2_FW_LINK_RATE_INVALID 0 +#define ATL2_FW_LINK_RATE_10M 1 +#define ATL2_FW_LINK_RATE_100M 2 +#define ATL2_FW_LINK_RATE_1G 3 +#define ATL2_FW_LINK_RATE_2G5 4 +#define ATL2_FW_LINK_RATE_5G 5 +#define ATL2_FW_LINK_RATE_10G 6 + +#define ATL2_HOST_MODE_INVALID 0U +#define ATL2_HOST_MODE_ACTIVE 1U +#define ATL2_HOST_MODE_SLEEP_PROXY 2U +#define ATL2_HOST_MODE_LOW_POWER 3U +#define ATL2_HOST_MODE_SHUTDOWN 4U + +#define ATL2_MIF_SHARED_BUF_IN 0x12000 +#define ATL2_MIF_SHARED_BUF_OUT 0x13000 + +#define ATL2_MTU_IN_OFF 0x0 +#define ATL2_MAC_ADDR_IN_OFF 0x8 +#define ATL2_LINK_CTRL_IN_OFF 0x10 +#define ATL2_LINK_OPTS_IN_OFF 0x18 + +#define ATL2_FW_OUT_OFF 0x8 +#define ATL2_LINK_STS_OUT_OFF 0x14 + +#define ATL2_DELAY_10 10 +#define ATL2_DELAY_100 100 + +#endif
\ No newline at end of file diff --git a/src/drivers/net/marvell/atl_hw.c b/src/drivers/net/marvell/atl_hw.c new file mode 100644 index 00000000..2dddb718 --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.c @@ -0,0 +1,321 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <ipxe/pci.h> +#include "aqc1xx.h" +#include "atl_hw.h" +#include <compiler.h> + + +int atl_hw_reset_flb_ ( struct atl_nic *nic ) +{ + uint32_t val; + int k = 0; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + ATL_WRITE_REG( (ATL_READ_REG(ATL_GLB_STD_CTRL) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + /* Kickstart MAC */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + ATL_WRITE_REG ( ATL_GEN_PROV9_ENABLE, ATL_GEN_PROV9 ); + + /* Reset SPI again because of possible interrupted SPI burst */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + mdelay ( ATL_DELAY_10_MNS ); + /* Clear SPI reset state */ + ATL_WRITE_REG ( val & ~ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* MAC Kickstart */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_MAC_KICK_START, ATL_GLB_CTRL2 ); + + for (k = 0; k < 1000; k++) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + + flb_status = flb_status & FLB_LOAD_STS; + if ( flb_status ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC (nic, "MAC kickstart failed\n" ); + return -EIO; + } + + /* FW reset */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RX_CTRL ) & + ~ATL_RX_CTRL_RST_DIS, ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_TX_CTRL ) & + ~ATL_TX_CTRL_RST_DIS, ATL_TX_CTRL ); + + ATL_WRITE_REG ( ATL_READ_REG ( ATL_MAC_PHY_CTRL ) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( ( ATL_READ_REG ( ATL_GLB_STD_CTRL ) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + for (k = 0; k < 1000; k++) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset_rbl_ ( struct atl_nic *nic ) +{ + uint32_t val, rbl_status; + int k; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + /* Alter RBL status */ + ATL_WRITE_REG ( POISON_SIGN, ATL_MPI_BOOT_EXIT_CODE ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG(ATL_RX_CTRL) & ~ATL_RX_CTRL_RST_DIS, + ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_TX_CTRL) & ~ATL_TX_CTRL_RST_DIS, + ATL_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_MAC_PHY_CTRL) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( (ATL_READ_REG(ATL_GLB_STD_CTRL) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL, ATL_GLB_CTRL2 ); + + /* Wait for RBL boot */ + for ( k = 0; k < 1000; k++ ) { + rbl_status = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ) & 0xFFFF; + if ( rbl_status && rbl_status != POISON_SIGN ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( !rbl_status || rbl_status == POISON_SIGN ) { + DBGC ( nic, "RBL Restart failed\n" ); + return -EIO; + } + + if ( rbl_status == FW_NOT_SUPPORT ) + return -ENOTSUP; + + for ( k = 0; k < 1000; k++ ) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset ( struct atl_nic *nic ) +{ + uint32_t boot_exit_code = 0; + uint32_t k; + int rbl_enabled; + uint32_t fw_ver; + uint32_t sem_timeout; + + for ( k = 0; k < 1000; ++k ) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + boot_exit_code = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ); + if ( flb_status != ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS || + boot_exit_code != 0 ) + break; + } + + if ( k == 1000 ) { + DBGC ( nic, "Neither RBL nor FLB firmware started\n" ); + return -ENOTSUP; + } + + rbl_enabled = (boot_exit_code != 0); + + fw_ver = ATL_READ_REG ( ATL_FW_VER ); + if ( ((fw_ver >> 24) & 0xFF) >= 4 ) { + sem_timeout = ATL_READ_REG ( ATL_SEM_TIMEOUT ); + if ( sem_timeout > ATL_SEM_MAX_TIMEOUT ) + sem_timeout = ATL_SEM_MAX_TIMEOUT; + + for ( k = 0; k < sem_timeout; ++k ) { + if ( ATL_READ_REG ( ATL_GLB_MCP_SEM4) ) + break; + + mdelay (ATL_DELAY_1_MNS); + } + for ( k = 0; k < sem_timeout; ++k ) { + if (ATL_READ_REG ( ATL_GLB_MCP_SEM5) ) + break; + + mdelay ( ATL_DELAY_1_MNS ); + } + } + + + if ( rbl_enabled ) + return atl_hw_reset_rbl_ ( nic ); + else + return atl_hw_reset_flb_ ( nic ); +} + +int atl_hw_start ( struct atl_nic *nic ) +{ + ATL_WRITE_REG ( ATL_LINK_ADV_AUTONEG, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_stop ( struct atl_nic *nic ) +{ + ATL_WRITE_REG ( ATL_SHUT_LINK, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_get_link ( struct atl_nic *nic ) +{ + return ( ATL_READ_REG ( ATL_LINK_ST) & ATL_LINK_ADV_AUTONEG ) != 0; +} + +int atl_hw_read_mem ( struct atl_nic *nic, uint32_t addr, uint32_t *buffer, + uint32_t size ) +{ + uint32_t i; + + for ( i = 0; i < 100; ++i ) { + if ( ATL_READ_REG( ATL_SEM_RAM) ) + break; + mdelay ( ATL_DELAY_1_MNS ); + } + if ( i == 100 ) { + DBGC (nic, "Semaphore Register not set\n" ); + return -EIO; + } + + ATL_WRITE_REG ( addr, ATL_MBOX_CTRL3 ); + + for ( i = 0; i < size; ++i, addr += 4 ) { + uint32_t j; + + ATL_WRITE_REG ( ATL_MBOX_CTRL1_START_MBOX_OPT, ATL_MBOX_CTRL1 ); + for ( j = 0; j < 10000; ++j ) { + if ( ATL_READ_REG (ATL_MBOX_CTRL3 ) != addr ) + break; + udelay ( ATL_DELAY_10_MNS ); + } + if ( j == 10000 ) { + DBGC (nic, "Reading from CTRL3 Register Failed\n" ); + return -EIO; + } + + buffer[i] = ATL_READ_REG ( ATL_MBOX_CTRL5 ); + } + + ATL_WRITE_REG( ATL_SEM_RAM_RESET, ATL_SEM_RAM ); + + return 0; +} + +int atl_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) +{ + uint32_t mac_addr[2] = {0}; + int err = 0; + uint32_t efuse_addr = ATL_READ_REG ( ATL_GLB_MCP_SP26 ); + + if ( efuse_addr != 0) { + uint32_t mac_efuse_addr = efuse_addr + 40 * sizeof(uint32_t); + err = atl_hw_read_mem ( nic, mac_efuse_addr, mac_addr, 2 ); + if ( err != 0 ) + return err; + + mac_addr[0] = cpu_to_be32 ( mac_addr[0] ); + mac_addr[1] = cpu_to_be32 ( mac_addr[1] ); + + memcpy ( mac, (uint8_t *)mac_addr, ATL_MAC_ADDRESS_SIZE ); + } + return 0; +} + +struct atl_hw_ops atl_hw = { + .reset = atl_hw_reset, + .start = atl_hw_start, + .stop = atl_hw_stop, + .get_link = atl_hw_get_link, + .get_mac = atl_hw_get_mac, +};
\ No newline at end of file diff --git a/src/drivers/net/marvell/atl_hw.h b/src/drivers/net/marvell/atl_hw.h new file mode 100644 index 00000000..0a20fbfc --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.h @@ -0,0 +1,83 @@ +/* + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __ATL_HW_H +#define __ATL_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL_GLB_STD_CTRL 0x0 +#define ATL_GLB_CTRL_RST_DIS 0x4000 +#define ATL_FW_VER 0x18 + +#define ATL_MPI_DAISY_CHAIN_STS 0x704 +#define ATL_MPI_RX_DAISY_CHAIN_DATA 0x04000000 +#define ATL_MPI_RX_DAISY_CHAIN_SOF 0x02000000 +#define FLB_LOAD_STS 0x10 + +#define ATL_MPI_BOOT_EXIT_CODE 0x388 + +#define ATL_SEM_TIMEOUT 0x348 +#define ATL_SEM_MAX_TIMEOUT 3000 + +#define ATL_GLB_CTRL2 0x404 +#define ATL_GLB_MCP_SEM1 0x3A0 +#define ATL_GBL_MCP_SEM1_RELEASE 0x1 + +#define ATL_GLB_MCP_SEM4 0x3AC +#define ATL_GLB_MCP_SEM5 0x3B0 +#define ATL_GLB_MCP_SP26 0x364 +#define ATL_MIF_PWR_GATING_EN_CTRL 0x32A8 + +#define ATL_GLB_NVR_PROV4 0x53C +#define ATL_GBL_NVR_PROV4_RESET 0x10 + + +#define ATL_GEN_PROV9 0x520 + +#define ATL_MAC_PHY_CTRL 0x00004000U +#define ATL_MAC_PHY_CTRL_RST_DIS 0x20000000U + +#define ATL_MIF_PWR_GATING_EN_CTRL_RESET 0x0 +#define ATL_GEN_PROV9_ENABLE 0x1 +#define ATL_GLB_CTRL2_MAC_KICK_START 0x180e0 +#define ATL_GLB_CTRL2_FW_RESET 0x80e0 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL 0x40e1 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL 0x40e0 +#define ATL_GLB_STD_CTRL_RESET 0x8000 +#define ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS 0x06000000 + +#define ATL_DELAY_1_MNS 1 +#define ATL_DELAY_10_MNS 10 +#define ATL_DELAY_15_MNS 15 +#define ATL_DELAY_50_MNS 50 + +#define ATL_MAC_ADDRESS_SIZE 6 +#define POISON_SIGN 0xDEAD +#define FW_NOT_SUPPORT 0xF1A7 + +#endif diff --git a/src/hci/commands/console_cmd.c b/src/hci/commands/console_cmd.c index ba472b9f..bd564726 100644 --- a/src/hci/commands/console_cmd.c +++ b/src/hci/commands/console_cmd.c @@ -70,6 +70,8 @@ static struct option_descriptor console_opts[] = { struct console_options, picture, parse_string ), OPTION_DESC ( "keep", 'k', no_argument, struct console_options, keep, parse_flag ), + OPTION_DESC ( "update", 'u', no_argument, + struct console_options, config.lazy_update, parse_flag ), }; /** "console" command descriptor */ diff --git a/src/hci/commands/efimap_cmd.c b/src/hci/commands/efimap_cmd.c new file mode 100644 index 00000000..c183cbc3 --- /dev/null +++ b/src/hci/commands/efimap_cmd.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdio.h> +#include <errno.h> +#include <getopt.h> +#include <string.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <usr/efiboot.h> + +/** @file + * + * EFIMAP command + * + */ + +/** "efimap" options */ +struct efimap_options {}; + +/** "efimap" option list */ +static struct option_descriptor efimap_opts[] = {}; + +/** "efimap" command descriptor */ +static struct command_descriptor efimap_cmd = + COMMAND_DESC ( struct efimap_options, efimap_opts, 0, 0, NULL); + +/** + * The "efimap" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int efimap_exec ( int argc, char **argv ) { + struct efimap_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &efimap_cmd, &opts ) ) != 0 ) + return rc; + + efi_boot_display_map (); + + return 0; +} + +/** EFIMAP command */ +struct command efimap_commands[] __command = { + { + .name = "efimap", + .exec = efimap_exec, + }, +}; diff --git a/src/hci/commands/login_cmd.c b/src/hci/commands/login_cmd.c index c9e19643..6ed76c6f 100644 --- a/src/hci/commands/login_cmd.c +++ b/src/hci/commands/login_cmd.c @@ -23,6 +23,7 @@ #include <string.h> #include <stdio.h> +#include <getopt.h> #include <ipxe/command.h> #include <ipxe/parseopt.h> #include <ipxe/login_ui.h> @@ -36,10 +37,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ /** "login" options */ -struct login_options {}; +struct login_options { + /** No Username */ + int nouser; +}; /** "login" option list */ -static struct option_descriptor login_opts[] = {}; +static struct option_descriptor login_opts[] = { + OPTION_DESC ( "nouser", 'n', no_argument, + struct login_options, nouser, parse_flag ), +}; /** "login" command descriptor */ static struct command_descriptor login_cmd = @@ -61,7 +68,7 @@ static int login_exec ( int argc, char **argv ) { return rc; /* Show login UI */ - if ( ( rc = login_ui() ) != 0 ) { + if ( ( rc = login_ui( opts.nouser ) ) != 0 ) { printf ( "Could not set credentials: %s\n", strerror ( rc ) ); return rc; diff --git a/src/hci/commands/menu_cmd.c b/src/hci/commands/menu_cmd.c index 76bce869..c8692f1a 100644 --- a/src/hci/commands/menu_cmd.c +++ b/src/hci/commands/menu_cmd.c @@ -118,6 +118,8 @@ struct item_options { int is_default; /** Use as a separator */ int is_gap; + /** Don't show; hotkey only */ + int is_hidden; }; /** "item" option list */ @@ -130,6 +132,8 @@ static struct option_descriptor item_opts[] = { struct item_options, is_default, parse_flag ), OPTION_DESC ( "gap", 'g', no_argument, struct item_options, is_gap, parse_flag ), + OPTION_DESC ( "hidden", 'i', no_argument, + struct item_options, is_hidden, parse_flag ), }; /** "item" command descriptor */ @@ -160,6 +164,12 @@ static int item_exec ( int argc, char **argv ) { if ( ! opts.is_gap ) label = argv[optind++]; /* May be NULL */ + /* Hidden entry without label and shortcut is pointless */ + if ( opts.is_hidden && ( ! opts.key || ! label || ! *label ) ) { + rc = -EINVAL; + goto err_invalid_argument; + } + /* Parse text, if present */ if ( optind < argc ) { text = concat_args ( &argv[optind] ); @@ -175,7 +185,7 @@ static int item_exec ( int argc, char **argv ) { /* Add menu item */ item = add_menu_item ( menu, label, ( text ? text : "" ), - opts.key, opts.is_default ); + opts.key, opts.is_default, opts.is_hidden ); if ( ! item ) { rc = -ENOMEM; goto err_add_menu_item; @@ -188,6 +198,7 @@ static int item_exec ( int argc, char **argv ) { err_parse_menu: free ( text ); err_parse_text: + err_invalid_argument: err_parse_options: return rc; } diff --git a/src/hci/tui/login_ui.c b/src/hci/tui/login_ui.c index 3c55325d..56fc2fa9 100644 --- a/src/hci/tui/login_ui.c +++ b/src/hci/tui/login_ui.c @@ -48,12 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EDITBOX_COL ( ( COLS / 2U ) - 10U ) #define EDITBOX_WIDTH 20U -int login_ui ( void ) { +int login_ui ( int nouser ) { char username[64]; char password[64]; struct edit_box username_box; struct edit_box password_box; - struct edit_box *current_box = &username_box; + struct edit_box *current_box = nouser ? &password_box : &username_box; int key; int rc = -EINPROGRESS; @@ -76,11 +76,15 @@ int login_ui ( void ) { color_set ( CPAIR_NORMAL, NULL ); erase(); attron ( A_BOLD ); - mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" ); + if ( ! nouser ) { + mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" ); + } mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" ); attroff ( A_BOLD ); color_set ( CPAIR_EDIT, NULL ); - draw_editbox ( &username_box ); + if ( ! nouser ) { + draw_editbox ( &username_box ); + } draw_editbox ( &password_box ); /* Main loop */ @@ -94,11 +98,15 @@ int login_ui ( void ) { current_box = &password_box; break; case KEY_UP: - current_box = &username_box; + if ( ! nouser ) { + current_box = &username_box; + } break; case TAB: - current_box = ( ( current_box == &username_box ) ? - &password_box : &username_box ); + if ( ! nouser ) { + current_box = ( ( current_box == &username_box ) ? + &password_box : &username_box ); + } break; case KEY_ENTER: if ( current_box == &username_box ) { diff --git a/src/hci/tui/menu_ui.c b/src/hci/tui/menu_ui.c index f9dd9d10..cb4edbbc 100644 --- a/src/hci/tui/menu_ui.c +++ b/src/hci/tui/menu_ui.c @@ -217,6 +217,8 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { break; default: i = 0; + + /* Check for shortcut. Visible items */ list_for_each_entry ( item, &ui->menu->items, list ) { if ( ! ( item->shortcut && @@ -231,6 +233,16 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { move = +1; } } + + /* Hidden items */ + list_for_each_entry ( item, &ui->menu->hidden_items, + list ) { + if ( item->shortcut && + ( item->shortcut == key ) ) { + *selected = item; + goto hidden_entry_selected; + } + } break; } } @@ -259,6 +271,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { } while ( ( rc == 0 ) && ! chosen ); + hidden_entry_selected: return rc; } diff --git a/src/include/ipxe/console.h b/src/include/ipxe/console.h index 1b764aac..ca8093a7 100644 --- a/src/include/ipxe/console.h +++ b/src/include/ipxe/console.h @@ -38,6 +38,8 @@ struct console_configuration { unsigned int bottom; /** Background picture, if any */ struct pixel_buffer *pixbuf; + /** Update mode: Don't re-init vesa mode, just update margins and bg image */ + int lazy_update; }; /** diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 0ab37230..afc260ba 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -224,6 +224,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_ecam ( ERRFILE_DRIVER | 0x00d30000 ) #define ERRFILE_pcibridge ( ERRFILE_DRIVER | 0x00d40000 ) #define ERRFILE_mnpnet ( ERRFILE_DRIVER | 0x00d50000 ) +#define ERRFILE_aqc1xx ( ERRFILE_DRIVER | 0x00df0000 ) +#define ERRFILE_atl_hw ( ERRFILE_DRIVER | 0x00d60000 ) +#define ERRFILE_atl2_hw ( ERRFILE_DRIVER | 0x00d70000 ) + #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) diff --git a/src/include/ipxe/login_ui.h b/src/include/ipxe/login_ui.h index 313e0734..07b1dd49 100644 --- a/src/include/ipxe/login_ui.h +++ b/src/include/ipxe/login_ui.h @@ -9,6 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -extern int login_ui ( void ); +extern int login_ui ( int nouser ); #endif /* _IPXE_LOGIN_UI_H */ diff --git a/src/include/ipxe/menu.h b/src/include/ipxe/menu.h index 3cc99be4..33965cfd 100644 --- a/src/include/ipxe/menu.h +++ b/src/include/ipxe/menu.h @@ -21,6 +21,8 @@ struct menu { const char *title; /** Menu items */ struct list_head items; + /** Hidden menu items, accessible via hotkey only */ + struct list_head hidden_items; }; /** A menu item */ @@ -40,7 +42,7 @@ struct menu_item { extern struct menu * create_menu ( const char *name, const char *title ); extern struct menu_item * add_menu_item ( struct menu *menu, const char *label, const char *text, int shortcut, - int is_default ); + int is_default, int is_hidden ); extern void destroy_menu ( struct menu *menu ); extern struct menu * find_menu ( const char *name ); extern int show_menu ( struct menu *menu, unsigned long timeout, diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 0301da12..ccb5e99f 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -424,6 +424,7 @@ extern const struct setting_type setting_type_uint32 __setting_type; extern const struct setting_type setting_type_hex __setting_type; extern const struct setting_type setting_type_hexhyp __setting_type; extern const struct setting_type setting_type_hexraw __setting_type; +extern const struct setting_type setting_type_md5 __setting_type; extern const struct setting_type setting_type_base64 __setting_type; extern const struct setting_type setting_type_uuid __setting_type; extern const struct setting_type setting_type_guid __setting_type; diff --git a/src/include/usr/efiboot.h b/src/include/usr/efiboot.h new file mode 100644 index 00000000..bd3065f0 --- /dev/null +++ b/src/include/usr/efiboot.h @@ -0,0 +1,15 @@ +#ifndef _USR_EFIBOOT_H +#define _USR_EFIBOOT_H + +/** @file + * + * EFI boot support + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +extern void efi_boot_display_map ( void ); +extern int efi_boot_local ( unsigned int drive, const char *filename ); + +#endif /* _USR_EFIBOOT_H */ diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 2f0187a0..a9c3d656 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -60,6 +60,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/efi/efi_path.h> #include <ipxe/efi/efi_null.h> #include <ipxe/efi/efi_block.h> +#include <usr/efiboot.h> /** ACPI table protocol protocol */ static EFI_ACPI_TABLE_PROTOCOL *acpi; @@ -990,6 +991,7 @@ static int efi_block_boot ( unsigned int drive, EFI_STATUS efirc; int rc; + /* Release SNP devices */ efi_snp_release(); diff --git a/src/interface/efi/efi_boot.c b/src/interface/efi/efi_boot.c new file mode 100644 index 00000000..19c31886 --- /dev/null +++ b/src/interface/efi/efi_boot.c @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2019 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * EFI boot local protocols + * + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ipxe/refcnt.h> +#include <ipxe/list.h> +#include <ipxe/uri.h> +#include <ipxe/interface.h> +#include <ipxe/blockdev.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/retry.h> +#include <ipxe/timer.h> +#include <ipxe/process.h> +#include <ipxe/sanboot.h> +#include <ipxe/iso9660.h> +#include <ipxe/acpi.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_strings.h> +#include <ipxe/efi/efi_snp.h> +#include <ipxe/efi/efi_path.h> +#include <ipxe/efi/efi_block.h> +#include <ipxe/efi/Guid/FileInfo.h> +#include <ipxe/efi/Guid/FileSystemInfo.h> +#include <ipxe/efi/Protocol/BlockIo.h> +#include <ipxe/efi/Protocol/SimpleFileSystem.h> +#include <ipxe/efi/Protocol/AcpiTable.h> + +static wchar_t efi_default_boot_filename[] = EFI_REMOVABLE_MEDIA_FILE_NAME; + +static EFI_DEVICE_PATH_PROTOCOL **DevicePathList; +static UINTN DevicePathListNum; +static EFI_HANDLE *SimpleFSHandleList; +static BOOLEAN efi_boot_map_initialized = FALSE; + +static EFI_HANDLE * efi_boot_get_handlelist ( EFI_GUID *ProtocolGuid ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE *HandleList; + UINTN Size; + EFI_STATUS efirc; + EFI_LOCATE_SEARCH_TYPE SearchType; + + /* NULL ProtocolGuid gets all handles in system */ + if ( ProtocolGuid ) + SearchType = ByProtocol; + else + SearchType = AllHandles; + + Size = 0; + HandleList = NULL; + + /* First call gets the handle list size and returns BUFFER_TOO_SMALL. */ + efirc = bs->LocateHandle ( SearchType, (EFI_GUID*) ProtocolGuid, + NULL, &Size, HandleList ); + if ( efirc == EFI_BUFFER_TOO_SMALL ) { + /* Alloc an extra handle for NULL list terminator */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, + ( Size + + sizeof ( EFI_HANDLE ) ), + (void **) &HandleList ) ) + != 0 ) { + return ( NULL ) ; + } + + efirc = bs->LocateHandle ( SearchType, (EFI_GUID*) ProtocolGuid, + NULL, &Size, HandleList ); + if ( HandleList ) + HandleList[Size / sizeof ( EFI_HANDLE )] = NULL; + } + + if ( EFI_ERROR ( efirc ) ) { + if ( HandleList ) + bs->FreePool ( HandleList ); + return ( NULL ) ; + } + + return ( HandleList ); +} + +static EFI_DEVICE_PATH_PROTOCOL * efi_boot_get_devpath ( EFI_HANDLE Handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS efirc; + + efirc = bs->HandleProtocol ( Handle, &efi_device_path_protocol_guid, + (VOID *) &DevicePath ); + + if ( EFI_ERROR ( efirc ) ) + return NULL; + else + return DevicePath; +} + +static void efi_boot_connect_pcibridges ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE *HandleList; + UINTN Count; + + HandleList = efi_boot_get_handlelist ( &efi_pci_root_bridge_io_protocol_guid ); + if ( HandleList == NULL ) { + DBG ( "EFIBOOT efi_boot_connect_pcibridges: no handles!\n" ); + return; + } + + for ( Count = 0 ; HandleList[Count] != NULL ; Count++ ) { + + DBG ( "EFIBOOT efi_boot_connect_pcibridges: connecting " + "handle %s\n", efi_handle_name ( HandleList[Count] ) ); + + (void) bs->ConnectController ( HandleList[Count], NULL, + NULL, 1 ); + + DBG ( "EFIBOOT: handle %s supports protocols:\n", + efi_handle_name ( HandleList[Count] ) ); + DBG_EFI_PROTOCOLS_IF ( LOG, HandleList[Count] ); + } + + bs->FreePool ( HandleList ); + + return; +} + +static int efi_vol_label( EFI_HANDLE handle, char *label_buf, + size_t label_buf_size ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_FILE_SYSTEM_INFO *info; + EFI_FILE_PROTOCOL *root; + EFI_STATUS efirc; + UINTN size; + int rc; + union { + void *interface; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + } u; + + /* Open file system protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, + &efi_simple_file_system_protocol_guid, + &u.interface, efi_image_handle, + handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -1; + DBG ( "Could not open filesystem on %s\n", + efi_handle_name ( handle ) ); + goto err_filesystem; + } + + /* Open root directory */ + if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { + rc = -1; + DBG ( "Could not open volume on %s\n", + efi_handle_name ( handle ) ); + goto err_volume; + } + + /* Get length of file system information */ + size = 0; + root->GetInfo ( root, &efi_file_system_info_id, &size, NULL ); + + /* Allocate file system information */ + info = malloc ( size ); + if ( ! info ) { + rc = -1; + goto err_alloc_info; + } + + /* Get file system information */ + if ( ( efirc = root->GetInfo ( root, &efi_file_system_info_id, &size, + info ) ) != 0 ) { + rc = -1; + DBG ( "could not get file system info on %s\n", + efi_handle_name ( handle ) ); + goto err_get_info; + } + DBG ( "Found %s with label \"%ls\"\n", + efi_handle_name ( handle ), info->VolumeLabel ); + + snprintf ( label_buf, label_buf_size, "%ls", info->VolumeLabel ); + + /* Success */ + rc = 0; + + err_get_info: + free ( info ); + err_alloc_info: + root->Close ( root ); + err_volume: + bs->CloseProtocol ( handle, &efi_simple_file_system_protocol_guid, + efi_image_handle, handle ); + err_filesystem: + return rc; +} + +static int efi_boot_create_map ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + UINTN Count; + UINTN i,j; + INTN NextIndex; + EFI_STATUS efirc; + EFI_HANDLE *TmpSimpleFSHandleList; + EFI_DEVICE_PATH_PROTOCOL **TmpDevicePathList; + VOID *buffer; + const char *path2; + char path1buf[256]; // 256 is the max buf + // size used internally + // by efi_devpath_text() + + DevicePathList = NULL; + DevicePathListNum = 0; + SimpleFSHandleList = NULL; + + efi_boot_connect_pcibridges (); + + TmpSimpleFSHandleList = efi_boot_get_handlelist ( &efi_simple_file_system_protocol_guid ); + if ( TmpSimpleFSHandleList == NULL ) { + /* valid - no filesystems found */ + efi_boot_map_initialized = TRUE; + return 0; + } + + /* Count number of handles */ + for ( Count = 0 ; TmpSimpleFSHandleList[Count] != NULL ; Count++ ); + + /* Allocate our temporary/local device path list */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, + ( Count * + sizeof ( EFI_DEVICE_PATH_PROTOCOL* ) + ), + &buffer ) ) != 0 ) { + DBG ( "EFIBOOT efi_boot_create_map: AllocatePool failed!\n" ); + bs->FreePool ( TmpSimpleFSHandleList ); + efi_boot_map_initialized = TRUE; + return -1; + } + TmpDevicePathList = (EFI_DEVICE_PATH_PROTOCOL **) buffer; + + /* Populate the devpath list */ + for ( i = 0 ; i < Count; i++ ) { + TmpDevicePathList[i] = efi_boot_get_devpath ( TmpSimpleFSHandleList[i] ); + } + + /* Allocate our global device path list */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, + ( Count * + sizeof ( EFI_DEVICE_PATH_PROTOCOL* ) + ), + &buffer ) ) != 0 ) { + DBG ( "EFIBOOT efi_boot_create_map: AllocatePool failed!\n" ); + bs->FreePool ( TmpSimpleFSHandleList ); + bs->FreePool ( TmpDevicePathList ); + efi_boot_map_initialized = TRUE; + + return -1; + } + DevicePathList = (EFI_DEVICE_PATH_PROTOCOL **) buffer; + + /* Allocate our global SimpleFSHandle list */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, + ( Count * + sizeof ( EFI_HANDLE ) + ), + &buffer ) ) != 0 ) { + DBG ( "EFIBOOT efi_boot_create_map: AllocatePool failed!\n" ); + bs->FreePool ( DevicePathList ); + DevicePathList = NULL; + bs->FreePool ( TmpSimpleFSHandleList ); + bs->FreePool ( TmpDevicePathList ); + efi_boot_map_initialized = TRUE; + + return -1; + } + SimpleFSHandleList = (EFI_HANDLE *) buffer; + + /* + * Populate the global SimpleFSHandle and DevicePath list. + * For consistency, order the list. + * Since each device path begins with PciRoot()/Pci() nodes, + * this will essentially give PCI BDF ordering. + * Put NULL devicepaths at end of the list (should not happen). + */ + for ( i = 0; i < Count; i++ ) { + NextIndex = -1; + path1buf[0]='\0'; + for ( j = 0; j < Count; j++ ) { + if ( TmpDevicePathList[j] == NULL ) + continue; + path2 = efi_devpath_text ( TmpDevicePathList[j] ); + if ( !path2 ) + continue; + + DBG ( "EFIBOOT %d: next=%d, comparing %s to %s\n", + (int) i, (int) NextIndex, path2, path1buf ); + if ( NextIndex == -1 || strncmp ( path2, path1buf, + 256 ) < 0 ) { + NextIndex = j; + strncpy ( path1buf, path2, 256 ); + } + } + if ( NextIndex != -1 ) { + DevicePathList[i] = TmpDevicePathList[NextIndex]; + SimpleFSHandleList[i] = TmpSimpleFSHandleList[NextIndex]; + TmpDevicePathList[NextIndex] = NULL; + } else { + DevicePathList[i] = NULL; + } + } + + DevicePathListNum = Count; + + bs->FreePool ( TmpSimpleFSHandleList ); + bs->FreePool ( TmpDevicePathList ); + + efi_boot_map_initialized = TRUE; + + return 0; +} + +static int efi_boot_local_fs ( EFI_DEVICE_PATH_PROTOCOL *dp, + const char *filename ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *boot_path; + FILEPATH_DEVICE_PATH *filepath; + EFI_DEVICE_PATH_PROTOCOL *end; + size_t prefix_len; + size_t filepath_len; + size_t boot_path_len; + EFI_HANDLE image = NULL; + EFI_STATUS efirc; + int rc; + + if ( dp == NULL ) + return -1; + + DBG ( "EFIBOOT efi_boot_local_fs: device path %s\n", + efi_devpath_text ( dp ) ); + + /* Construct device path for boot image */ + end = efi_path_end ( dp ); + prefix_len = ( ( (void *) end ) - ( (void *) dp ) ); + filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + + ( filename ? ( ( strlen ( filename ) + 1 ) * + sizeof ( filepath->PathName[0] ) ): + sizeof ( efi_default_boot_filename ) ) ); + + boot_path_len = ( prefix_len + filepath_len + sizeof ( *end ) ); + boot_path = zalloc ( boot_path_len ); + if ( !boot_path ) { + rc = -1; + goto err_alloc_path; + } + + memcpy ( boot_path, dp, prefix_len ); + filepath = ( ( (void *) boot_path ) + prefix_len ); + filepath->Header.Type = MEDIA_DEVICE_PATH; + filepath->Header.SubType = MEDIA_FILEPATH_DP; + filepath->Header.Length[0] = ( filepath_len & 0xff ); + filepath->Header.Length[1] = ( filepath_len >> 8 ); + + if ( filename ) { + efi_sprintf ( filepath->PathName, "%s", filename ); + } else { + memcpy ( filepath->PathName, efi_default_boot_filename, + sizeof ( efi_default_boot_filename ) ); + } + + end = ( ( (void *) filepath ) + filepath_len ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + /* Release SNP devices */ + efi_snp_release (); + + DBG ( "EFIBOOT attempt to load %s\n", efi_devpath_text ( boot_path ) ); + + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, boot_path, + NULL, 0, &image ) ) != 0 ) { + rc = -1; + DBG ( "EFIBOOT failed to load image\n" ); + goto err_load_image; + } + + DBG ( "EFIBOOT successfully loaded image\n" ); + DBG ( "EFIBOOT trying to start %s\n", + efi_devpath_text ( boot_path ) ); + + efirc = bs->StartImage ( image, NULL, NULL ); + if ( EFI_ERROR ( efirc ) ) + rc = -1; + else + rc = 0; + + DBG ( "EFIBOOT boot image returned: %d\n", rc ); + + bs->UnloadImage ( image ); + +err_load_image: + efi_snp_claim (); + free ( boot_path ); +err_alloc_path: + + return rc; +} + +void efi_boot_display_map ( void ) { + char vol_label[256]; + UINTN i; + int rc; + + if ( !efi_boot_map_initialized ) + efi_boot_create_map (); + + printf ( "Drive#\t[Volume Label] Path\n" ); + printf ( "------\t-------------------\n" ); + for ( i = 0 ; i < DevicePathListNum ; i++ ) { + if ( DevicePathList[i] != NULL ) { + rc = efi_vol_label ( SimpleFSHandleList[i], + vol_label, 256 ); + if ( rc || *vol_label == '\0' ) + strcpy(vol_label, "NO VOLUME LABEL"); + printf ( "%d \t[%s] %s\n", (int) i, vol_label, + efi_devpath_text ( DevicePathList[i] ) ); + } + } +} + +int efi_boot_local ( unsigned int drive, const char *filename ) { + + if ( !efi_boot_map_initialized ) + efi_boot_create_map (); + + if ( DevicePathListNum == 0 || drive > ( DevicePathListNum-1 ) || + DevicePathList[drive] == NULL ) { + printf ( "ERROR: Invalid drive number %#02x\n", drive ); + return -1; + } + + efi_boot_local_fs ( DevicePathList[drive], filename ); + + return 0; +} diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index d388e031..e3c4d001 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -519,68 +519,70 @@ static int efifb_init ( struct console_configuration *config ) { EFI_STATUS efirc; int rc; - /* Locate graphics output protocol */ - if ( ( efirc = bs->LocateProtocol ( &efi_graphics_output_protocol_guid, - NULL, &interface ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not locate graphics output " - "protocol: %s\n", strerror ( rc ) ); - goto err_locate_gop; - } - efifb.gop = interface; + if ( ! config->lazy_update ) { + /* Locate graphics output protocol */ + if ( ( efirc = bs->LocateProtocol ( &efi_graphics_output_protocol_guid, + NULL, &interface ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efifb, "EFIFB could not locate graphics output " + "protocol: %s\n", strerror ( rc ) ); + goto err_locate_gop; + } + efifb.gop = interface; - /* Locate HII font protocol */ - if ( ( efirc = bs->LocateProtocol ( &efi_hii_font_protocol_guid, - NULL, &interface ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not locate HII font protocol: %s\n", - strerror ( rc ) ); - goto err_locate_hiifont; - } - efifb.hiifont = interface; + /* Locate HII font protocol */ + if ( ( efirc = bs->LocateProtocol ( &efi_hii_font_protocol_guid, + NULL, &interface ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efifb, "EFIFB could not locate HII font protocol: %s\n", + strerror ( rc ) ); + goto err_locate_hiifont; + } + efifb.hiifont = interface; - /* Locate glyphs */ - if ( ( rc = efifb_glyphs() ) != 0 ) - goto err_glyphs; + /* Locate glyphs */ + if ( ( rc = efifb_glyphs() ) != 0 ) + goto err_glyphs; - /* Save original mode */ - efifb.saved_mode = efifb.gop->Mode->Mode; + /* Save original mode */ + efifb.saved_mode = efifb.gop->Mode->Mode; - /* Select mode */ - if ( ( mode = efifb_select_mode ( config->width, config->height, - config->depth ) ) < 0 ) { - rc = mode; - goto err_select_mode; - } + /* Select mode */ + if ( ( mode = efifb_select_mode ( config->width, config->height, + config->depth ) ) < 0 ) { + rc = mode; + goto err_select_mode; + } - /* Set mode */ - if ( ( efirc = efifb.gop->SetMode ( efifb.gop, mode ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not set mode %d: %s\n", - mode, strerror ( rc ) ); - goto err_set_mode; - } - info = efifb.gop->Mode->Info; - - /* Populate colour map */ - bpp = efifb_colour_map ( info, &efifb.map ); - if ( bpp < 0 ) { - rc = bpp; - DBGC ( &efifb, "EFIFB could not build colour map for " - "mode %d: %s\n", mode, strerror ( rc ) ); - goto err_map; - } + /* Set mode */ + if ( ( efirc = efifb.gop->SetMode ( efifb.gop, mode ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efifb, "EFIFB could not set mode %d: %s\n", + mode, strerror ( rc ) ); + goto err_set_mode; + } + info = efifb.gop->Mode->Info; - /* Populate pixel geometry */ - efifb.pixel.width = info->HorizontalResolution; - efifb.pixel.height = info->VerticalResolution; - efifb.pixel.len = ( ( bpp + 7 ) / 8 ); - efifb.pixel.stride = ( efifb.pixel.len * info->PixelsPerScanLine ); + /* Populate colour map */ + bpp = efifb_colour_map ( info, &efifb.map ); + if ( bpp < 0 ) { + rc = bpp; + DBGC ( &efifb, "EFIFB could not build colour map for " + "mode %d: %s\n", mode, strerror ( rc ) ); + goto err_map; + } - /* Populate frame buffer address */ - efifb.start = efifb.gop->Mode->FrameBufferBase; - DBGC ( &efifb, "EFIFB using mode %d (%dx%d %dbpp at %#08lx)\n", - mode, efifb.pixel.width, efifb.pixel.height, bpp, efifb.start ); + /* Populate pixel geometry */ + efifb.pixel.width = info->HorizontalResolution; + efifb.pixel.height = info->VerticalResolution; + efifb.pixel.len = ( ( bpp + 7 ) / 8 ); + efifb.pixel.stride = ( efifb.pixel.len * info->PixelsPerScanLine ); + + /* Populate frame buffer address */ + efifb.start = efifb.gop->Mode->FrameBufferBase; + DBGC ( &efifb, "EFIFB using mode %d (%dx%d %dbpp at %#08lx)\n", + mode, efifb.pixel.width, efifb.pixel.height, bpp, efifb.start ); +} /* Initialise frame buffer console */ if ( ( rc = fbcon_init ( &efifb.fbcon, phys_to_user ( efifb.start ), @@ -638,13 +640,32 @@ static void efifb_putchar ( int character ) { static int efifb_configure ( struct console_configuration *config ) { int rc; - /* Reset console, if applicable */ - if ( ! efifb_console.disabled ) { - efifb_fini(); - efi_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; - ansicol_reset_magic(); + if ( config && config->lazy_update ) { + if ( efifb_console.disabled ) + return 0; + /* No width/height given, use current so we can update the border */ + if ( ( config->width == 0 ) || ( config->height == 0 ) ) { + if ( ( efifb.pixel.width == 0 ) || ( efifb.pixel.height == 0 ) ) { + return -EINVAL; + } + config->width = efifb.pixel.width; + config->height = efifb.pixel.height; + } else { + /* Otherwise make sure the new dimensions match the old ones */ + if ( ( efifb.pixel.width != config->width ) || + ( efifb.pixel.height != config->height ) ) { + return -EINVAL; + } + } + } else { + /* Reset console, if applicable */ + if ( ! efifb_console.disabled ) { + efifb_fini(); + efi_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; + ansicol_reset_magic(); + } + efifb_console.disabled = CONSOLE_DISABLED; } - efifb_console.disabled = CONSOLE_DISABLED; /* Do nothing more unless we have a usable configuration */ if ( ( config == NULL ) || @@ -656,13 +677,15 @@ static int efifb_configure ( struct console_configuration *config ) { if ( ( rc = efifb_init ( config ) ) != 0 ) return rc; - /* Mark console as enabled */ - efifb_console.disabled = 0; - efi_console.disabled |= CONSOLE_DISABLED_OUTPUT; + if ( ! config->lazy_update ) { + /* Mark console as enabled */ + efifb_console.disabled = 0; + efi_console.disabled |= CONSOLE_DISABLED_OUTPUT; - /* Set magic colour to transparent if we have a background picture */ - if ( config->pixbuf ) - ansicol_set_magic_transparent(); + /* Set magic colour to transparent if we have a background picture */ + if ( config->pixbuf ) + ansicol_set_magic_transparent(); + } return 0; } diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c index ec6d93a1..b2881424 100644 --- a/src/interface/efi/efi_local.c +++ b/src/interface/efi/efi_local.c @@ -247,6 +247,62 @@ static int efi_local_open_root ( struct efi_local *local, EFI_HANDLE device, } /** + * Open root filesystem of specified volume by index + * + * @v local Local file + * @v index Volume index + * @ret rc Return status code + */ +static int efi_local_open_volume_index ( struct efi_local *local, + UINTN index ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID *protocol = &efi_simple_file_system_protocol_guid; + EFI_FILE_PROTOCOL *root; + EFI_HANDLE *handles; + EFI_HANDLE device; + UINTN num_handles; + EFI_STATUS efirc; + int rc; + + /* Locate all filesystem handles */ + if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, protocol, + NULL, &num_handles, + &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( local, "LOCAL %p could not enumerate handles: " + "%s\n", local, strerror ( rc ) ); + return rc; + } + + /* Find matching handle */ + if ( index >= num_handles ) { + rc = -ENOENT; + } else { + /* Get this device handle */ + device = handles[index]; + + /* Open root directory */ + if ( ( rc = efi_local_open_root ( local, device, &root ) ) == 0 && root ) { + local->root = root; + rc = 0; + } else { + rc = -EACCES; + } + } + + /* Free handles, if applicable */ + bs->FreePool ( handles ); + + /* Fail if we found no matching handle */ + if ( ! local->root ) { + DBGC ( local, "LOCAL %p found no matching device with index %u\n", + local, (unsigned int)index ); + } + + return rc; +} + +/** * Open root filesystem of specified volume * * @v local Local file @@ -581,19 +637,45 @@ static struct process_descriptor efi_local_process_desc = */ static int efi_local_open ( struct interface *xfer, struct uri *uri ) { struct efi_local *local; + int vol; + int rc = 0; /* Allocate and initialise structure */ local = zalloc ( sizeof ( *local ) ); if ( ! local ) return -ENOMEM; ref_init ( &local->refcnt, efi_local_free ); - intf_init ( &local->xfer, &efi_local_xfer_desc, &local->refcnt ); - process_init_stopped ( &local->process, &efi_local_process_desc, - &local->refcnt ); local->uri = uri_get ( uri ); local->volume = ( ( uri->host && uri->host[0] ) ? uri->host : NULL ); local->path = ( uri->opaque ? uri->opaque : uri->path ); + if ( local->path && local->volume && strcmp ( local->volume, "*" ) == 0 ) { + /* Open on any volume */ + vol = 0; + while ( ( rc = efi_local_open_volume_index ( local, vol++ ) ) != -ENOENT ) { + if ( rc != 0 ) + continue; + /* Open specified path */ + if ( ( rc = efi_local_open_path ( local ) ) != 0 ) { + local->root->Close ( local->root ); + local->root = NULL; + continue; + } + /* Success */ + break; + } + if ( rc != 0 ) { + DBGC ( local, "LOCAL %p could not find %s on any partition\n", + local, local->path ); + ref_put ( &local->refcnt ); + return -ENOENT; + } + } + + intf_init ( &local->xfer, &efi_local_xfer_desc, &local->refcnt ); + process_init_stopped ( &local->process, &efi_local_process_desc, + &local->refcnt ); + /* Start download process */ process_add ( &local->process ); |