EFI_TPL previous;
};
+/** An EFI dropped task priority level */
+struct efi_dropped_tpl {
+ /** Current TPL */
+ EFI_TPL current;
+};
+
/** An EFI protocol used by iPXE */
struct efi_protocol {
/** GUID */
EFI_SYSTEM_TABLE *systab );
extern void efi_raise_tpl ( struct efi_saved_tpl *tpl );
extern void efi_restore_tpl ( struct efi_saved_tpl *tpl );
+extern void efi_drop_tpl ( struct efi_dropped_tpl *tpl );
+extern void efi_undrop_tpl ( struct efi_dropped_tpl *tpl );
extern int efi_open_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
void **interface );
extern int efi_open_unsafe_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE driverlist[2] = { driver, NULL };
EFI_HANDLE *drivers = ( driver ? driverlist : NULL );
+ struct efi_dropped_tpl tpl;
EFI_STATUS efirc;
int rc;
DBGC ( device, "%s driver at %s TPL\n",
( driver ? efi_handle_name ( driver ) : "any" ),
efi_tpl_name ( efi_external_tpl ) );
- bs->RestoreTPL ( efi_external_tpl );
+ efi_drop_tpl ( &tpl );
efirc = bs->ConnectController ( device, drivers, NULL, TRUE );
- bs->RaiseTPL ( efi_internal_tpl );
+ efi_undrop_tpl ( &tpl );
if ( efirc != 0 ) {
rc = -EEFI_CONNECT ( efirc );
DBGC ( device, "EFI %s could not connect: %s\n",
*/
int efi_disconnect ( EFI_HANDLE device, EFI_HANDLE driver ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_dropped_tpl tpl;
EFI_STATUS efirc;
int rc;
DBGC ( device, "%s driver at %s TPL\n",
( driver ? efi_handle_name ( driver ) : "any" ),
efi_tpl_name ( efi_external_tpl ) );
- bs->RestoreTPL ( efi_external_tpl );
+ efi_drop_tpl ( &tpl );
efirc = bs->DisconnectController ( device, driver, NULL );
- bs->RaiseTPL ( efi_internal_tpl );
+ efi_undrop_tpl ( &tpl );
if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not disconnect: %s\n",
/** Event used to wait for timer tick */
static EFI_EVENT tick;
+/** Dropped TPL */
+static struct efi_dropped_tpl efi_entropy_tpl;
+
/**
* Enable entropy gathering
*
int rc;
/* Drop to external TPL to allow timer tick event to take place */
- bs->RestoreTPL ( efi_external_tpl );
+ efi_drop_tpl ( &efi_entropy_tpl );
/* Create timer tick event */
if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
bs->CloseEvent ( tick );
/* Return to internal TPL */
- bs->RaiseTPL ( efi_internal_tpl );
+ efi_undrop_tpl ( &efi_entropy_tpl );
}
/**
}
/**
- * Restore task priority level
+ * Restore saved task priority level
*
* @v tpl Saved TPL
*/
/* Restore TPL */
bs->RestoreTPL ( tpl->current );
}
+
+/**
+ * Drop task priority level temporarily to external level
+ *
+ * @v tpl Dropped TPL
+ */
+void efi_drop_tpl ( struct efi_dropped_tpl *tpl ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+ /* Raise TPL temporarily to discover current TPL */
+ tpl->current = bs->RaiseTPL ( TPL_HIGH_LEVEL );
+ bs->RestoreTPL ( tpl->current );
+
+ /* Drop to external TPL */
+ bs->RestoreTPL ( efi_external_tpl );
+}
+
+/**
+ * Restore dropped task priority level
+ *
+ * @v tpl Dropped TPL
+ */
+void efi_undrop_tpl ( struct efi_dropped_tpl *tpl ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+ /* Raise back to original TPL */
+ bs->RaiseTPL ( tpl->current );
+}
* @ret ticks Current time, in ticks
*/
static unsigned long efi_currticks ( void ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_dropped_tpl tpl;
/* UEFI manages to ingeniously combine the worst aspects of
* both polling and interrupt-driven designs. There is no way
if ( efi_shutdown_in_progress ) {
efi_jiffies++;
} else {
- bs->RestoreTPL ( efi_external_tpl );
- bs->RaiseTPL ( efi_internal_tpl );
+ efi_drop_tpl ( &tpl );
+ efi_undrop_tpl ( &tpl );
}
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );