summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile1
-rw-r--r--src/arch/x86/interface/pcbios/vesafb.c233
-rw-r--r--src/config/config_efi.c8
-rw-r--r--src/config/general.h1
-rw-r--r--src/core/fbcon.c72
-rw-r--r--src/core/menu.c13
-rw-r--r--src/core/settings.c47
-rw-r--r--src/drivers/net/marvell/aqc1xx.c643
-rw-r--r--src/drivers/net/marvell/aqc1xx.h270
-rw-r--r--src/drivers/net/marvell/atl2_hw.c235
-rw-r--r--src/drivers/net/marvell/atl2_hw.h94
-rw-r--r--src/drivers/net/marvell/atl_hw.c321
-rw-r--r--src/drivers/net/marvell/atl_hw.h83
-rw-r--r--src/hci/commands/console_cmd.c2
-rw-r--r--src/hci/commands/efimap_cmd.c77
-rw-r--r--src/hci/commands/login_cmd.c13
-rw-r--r--src/hci/commands/menu_cmd.c13
-rw-r--r--src/hci/tui/login_ui.c22
-rw-r--r--src/hci/tui/menu_ui.c13
-rw-r--r--src/include/ipxe/console.h2
-rw-r--r--src/include/ipxe/errfile.h4
-rw-r--r--src/include/ipxe/login_ui.h2
-rw-r--r--src/include/ipxe/menu.h4
-rw-r--r--src/include/ipxe/settings.h1
-rw-r--r--src/include/usr/efiboot.h15
-rw-r--r--src/interface/efi/efi_block.c2
-rw-r--r--src/interface/efi/efi_boot.c475
-rw-r--r--src/interface/efi/efi_fbcon.c157
-rw-r--r--src/interface/efi/efi_local.c88
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 );