os: implement waitable management.

This implements waitable management for Events (and
implements Events). It also refactors PM to use new
Event/Waitable semantics, and also adds STS_ASSERT
as a macro for asserting a boolean expression. The
rest of stratosphere has been refactored to use
STS_ASSERT whenever possible.
This commit is contained in:
Michael Scire
2019-09-27 18:04:58 -07:00
committed by SciresM
parent e07011be32
commit 609a302e16
108 changed files with 2752 additions and 1223 deletions

View File

@@ -29,9 +29,7 @@ namespace sts::i2c::driver::impl {
/* Ensure we're good if this isn't our first session. */
if (this->open_sessions > 1) {
if (this->speed_mode != speed_mode) {
std::abort();
}
STS_ASSERT(this->speed_mode == speed_mode);
return;
}
@@ -58,7 +56,7 @@ namespace sts::i2c::driver::impl {
}
/* Close interrupt event. */
eventClose(&this->interrupt_event);
this->interrupt_event.Finalize();
/* Close PCV. */
pcv::Finalize();
@@ -158,10 +156,10 @@ namespace sts::i2c::driver::impl {
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->interrupt_event.Reset();
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
this->interrupt_event.Reset();
return ResultI2cTimedOut;
}
@@ -181,10 +179,10 @@ namespace sts::i2c::driver::impl {
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->interrupt_event.Reset();
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
this->interrupt_event.Reset();
return ResultI2cTimedOut;
}
}
@@ -206,11 +204,11 @@ namespace sts::i2c::driver::impl {
/* Receive bytes. */
while (remaining > 0) {
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->interrupt_event.Reset();
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
this->HandleTransactionResult(ResultI2cBusBusy);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
this->interrupt_event.Reset();
return ResultI2cTimedOut;
}
@@ -245,16 +243,9 @@ namespace sts::i2c::driver::impl {
static constexpr u64 s_interrupts[] = {
0x46, 0x74, 0x7C, 0x98, 0x55, 0x5F
};
if (ConvertToIndex(bus) >= util::size(s_interrupts)) {
std::abort();
}
Handle evt_h;
if (R_FAILED(svcCreateInterruptEvent(&evt_h, s_interrupts[ConvertToIndex(bus)], 1))) {
std::abort();
}
eventLoadRemote(&this->interrupt_event, evt_h, false);
const auto index = ConvertToIndex(bus);
STS_ASSERT(index < util::size(s_interrupts));
R_ASSERT(this->interrupt_event.Initialize(s_interrupts[index], false));
}
void BusAccessor::SetClock(SpeedMode speed_mode) {
@@ -307,29 +298,17 @@ namespace sts::i2c::driver::impl {
reg::Read(&this->i2c_registers->I2C_I2C_CNFG_0);
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1)))) {
std::abort();
}
if (R_FAILED(pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
R_ASSERT(pcv::SetReset(this->pcv_module, true));
R_ASSERT(pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1)));
R_ASSERT(pcv::SetReset(this->pcv_module, false));
}
}
void BusAccessor::ResetController() const {
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(pcv::SetClockRate(this->pcv_module, 81'600'000))) {
std::abort();
}
if (R_FAILED(pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
R_ASSERT(pcv::SetReset(this->pcv_module, true));
R_ASSERT(pcv::SetClockRate(this->pcv_module, 81'600'000));
R_ASSERT(pcv::SetReset(this->pcv_module, false));
}
}
@@ -388,9 +367,7 @@ namespace sts::i2c::driver::impl {
}
void BusAccessor::DisableClock() {
if (R_FAILED(pcv::SetClockEnabled(this->pcv_module, false))) {
std::abort();
}
R_ASSERT(pcv::SetClockEnabled(this->pcv_module, false));
}
void BusAccessor::SetPacketMode() {
@@ -435,24 +412,21 @@ namespace sts::i2c::driver::impl {
}
void BusAccessor::HandleTransactionResult(Result result) {
if (R_FAILED(result)) {
if (result == ResultI2cNoAck || result == ResultI2cBusBusy) {
R_TRY_CATCH(result) {
R_CATCH_MANY(ResultI2cNoAck, ResultI2cBusBusy) {
this->ResetController();
this->SetClock(this->speed_mode);
this->SetPacketMode();
this->FlushFifos();
} else {
std::abort();
}
}
} R_END_TRY_CATCH_WITH_ASSERT;
}
Result BusAccessor::GetAndHandleTransactionResult() {
const Result transaction_res = this->GetTransactionResult();
R_TRY_CLEANUP(transaction_res, {
this->HandleTransactionResult(transaction_res);
R_TRY_CLEANUP(this->GetTransactionResult(), {
this->HandleTransactionResult(R_CLEANUP_RESULT);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
this->interrupt_event.Reset();
});
return ResultSuccess;
}

View File

@@ -31,7 +31,7 @@ namespace sts::i2c::driver::impl {
};
static constexpr u64 InterruptTimeout = 100'000'000ul;
private:
Event interrupt_event;
os::InterruptEvent interrupt_event;
os::Mutex open_mutex;
os::Mutex register_mutex;
Registers *i2c_registers = nullptr;

View File

@@ -88,37 +88,37 @@ namespace sts::i2c::driver::impl {
Bus GetDeviceBus(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].bus;
}
u32 GetDeviceSlaveAddress(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].slave_address;
}
AddressingMode GetDeviceAddressingMode(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].addressing_mode;
}
SpeedMode GetDeviceSpeedMode(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].speed_mode;
}
u32 GetDeviceMaxRetries(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].max_retries;
}
u64 GetDeviceRetryWaitTime(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
STS_ASSERT(dev_idx != DeviceInvalidIndex);
return g_device_configs[dev_idx].retry_wait_time;
}

View File

@@ -43,9 +43,7 @@ namespace sts::i2c::driver::impl {
}
constexpr inline Bus ConvertFromIndex(size_t idx) {
if (idx >= static_cast<size_t>(Bus::Count)) {
std::abort();
}
STS_ASSERT(idx < static_cast<size_t>(Bus::Count));
return static_cast<Bus>(idx);
}

View File

@@ -29,9 +29,7 @@ namespace sts::i2c::driver::impl {
void ResourceManager::Finalize() {
std::scoped_lock lk(this->initialize_mutex);
if (this->ref_cnt == 0) {
std::abort();
}
STS_ASSERT(this->ref_cnt > 0);
this->ref_cnt--;
if (this->ref_cnt > 0) {
return;
@@ -61,14 +59,11 @@ namespace sts::i2c::driver::impl {
/* Get, open session. */
{
std::scoped_lock lk(this->session_open_mutex);
if (out_session == nullptr || bus >= Bus::Count) {
std::abort();
}
STS_ASSERT(out_session != nullptr);
STS_ASSERT(bus < Bus::Count);
session_id = GetFreeSessionId();
if (session_id == InvalidSessionId) {
std::abort();
}
STS_ASSERT(session_id != InvalidSessionId);
if ((bus == Bus::I2C2 || bus == Bus::I2C3) && (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() == 0 && this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() == 0)) {
@@ -83,12 +78,8 @@ namespace sts::i2c::driver::impl {
this->sessions[session_id].Start();
if (need_enable_ldo6) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) {
std::abort();
}
if (R_FAILED(pcv::SetVoltageEnabled(10, true))) {
std::abort();
}
R_ASSERT(pcv::SetVoltageValue(10, 2'900'000));
R_ASSERT(pcv::SetVoltageEnabled(10, true));
pcv::Finalize();
svcSleepThread(560'000ul);
}
@@ -99,9 +90,7 @@ namespace sts::i2c::driver::impl {
/* Get, open session. */
{
std::scoped_lock lk(this->session_open_mutex);
if (!this->sessions[session.session_id].IsOpen()) {
std::abort();
}
STS_ASSERT(this->sessions[session.session_id].IsOpen());
this->sessions[session.session_id].Close();
@@ -113,18 +102,14 @@ namespace sts::i2c::driver::impl {
if (need_disable_ldo6) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageEnabled(10, false))) {
std::abort();
}
R_ASSERT(pcv::SetVoltageEnabled(10, false));
pcv::Finalize();
}
}
void ResourceManager::SuspendBuses() {
if (this->ref_cnt == 0) {
std::abort();
}
STS_ASSERT(this->ref_cnt > 0);
if (!this->suspended) {
{
@@ -137,27 +122,19 @@ namespace sts::i2c::driver::impl {
}
}
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageEnabled(10, false))) {
std::abort();
}
R_ASSERT(pcv::SetVoltageEnabled(10, false));
pcv::Finalize();
}
}
void ResourceManager::ResumeBuses() {
if (this->ref_cnt == 0) {
std::abort();
}
STS_ASSERT(this->ref_cnt > 0);
if (this->suspended) {
if (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() > 0 || this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() > 0) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) {
std::abort();
}
if (R_FAILED(pcv::SetVoltageEnabled(10, true))) {
std::abort();
}
R_ASSERT(pcv::SetVoltageValue(10, 2'900'000));
R_ASSERT(pcv::SetVoltageEnabled(10, true));
pcv::Finalize();
svcSleepThread(1'560'000ul);
}
@@ -174,9 +151,7 @@ namespace sts::i2c::driver::impl {
}
void ResourceManager::SuspendPowerBus() {
if (this->ref_cnt == 0) {
std::abort();
}
STS_ASSERT(this->ref_cnt > 0);
std::scoped_lock lk(this->session_open_mutex);
if (!this->power_bus_suspended) {
@@ -188,9 +163,7 @@ namespace sts::i2c::driver::impl {
}
void ResourceManager::ResumePowerBus() {
if (this->ref_cnt == 0) {
std::abort();
}
STS_ASSERT(this->ref_cnt > 0);
std::scoped_lock lk(this->session_open_mutex);
if (this->power_bus_suspended) {