SPU: Implement sys_spu_initialize and limit of physical SPU threads

This commit is contained in:
Eladash 2021-07-30 18:48:32 +03:00 committed by Ivan
parent af89eb5404
commit 06f4dfb9f1

View file

@ -198,17 +198,82 @@ std::pair<named_thread<spu_thread>*, std::shared_ptr<lv2_spu_group>> lv2_spu_gro
return res; return res;
} }
namespace
{
struct limits_data
{
u32 physical = 0;
u32 raw_spu = 0;
u32 controllable = 0;
u32 spu_limit = umax;
u32 raw_limit = umax;
};
struct spu_limits_t
{
u32 max_raw = 0;
u32 max_spu = 6;
shared_mutex mutex;
bool check(const limits_data& init) const
{
u32 physical_spus_count = init.physical;
u32 raw_spu_count = init.raw_spu;
u32 controllable_spu_count = init.controllable;
const u32 spu_limit = init.spu_limit != umax ? init.spu_limit : max_spu;
const u32 raw_limit = init.raw_limit != umax ? init.raw_limit : max_raw;
idm::select<lv2_spu_group>([&](u32, lv2_spu_group& group)
{
if (group.has_scheduler_context)
{
controllable_spu_count = std::max(controllable_spu_count, group.max_num);
}
else
{
physical_spus_count += group.max_num;
}
});
raw_spu_count += spu_thread::g_raw_spu_ctr;
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count + controllable_spu_count > spu_limit)
{
return false;
}
return true;
}
};
} // annonymous namespace
error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_spu) error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_spu)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
sys_spu.warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); sys_spu.warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
auto& limits = g_fxo->get<spu_limits_t>();
if (max_raw_spu > 5) if (max_raw_spu > 5)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
// NOTE: This value can be changed by VSH in theory
max_usable_spu = 6;
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.spu_limit = max_usable_spu - max_raw_spu, .raw_limit = max_raw_spu}))
{
return CELL_EBUSY;
}
limits.max_raw = max_raw_spu;
limits.max_spu = max_usable_spu - max_raw_spu;
return CELL_OK; return CELL_OK;
} }
@ -505,7 +570,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
bool use_scheduler = true; bool use_scheduler = true;
bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER); bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER);
bool needs_root = false; bool needs_root = false;
u32 max_threads = 6; // TODO: max num value should be affected by sys_spu_initialize() settings u32 max_threads = 6;
u32 min_threads = 1; u32 min_threads = 1;
u32 mem_size = 0; u32 mem_size = 0;
lv2_memory_container* ct{}; lv2_memory_container* ct{};
@ -620,6 +685,16 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
} }
} }
auto& limits = g_fxo->get<spu_limits_t>();
std::lock_guard lock(limits.mutex);
if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num}))
{
ct->used -= mem_size;
return CELL_EBUSY;
}
const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr->name.get_ptr(), std::max<u32>(attr->nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size); const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr->name.get_ptr(), std::max<u32>(attr->nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size);
if (!group) if (!group)
@ -1821,7 +1896,14 @@ error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<void> at
sys_spu.warning("sys_raw_spu_create(id=*0x%x, attr=*0x%x)", id, attr); sys_spu.warning("sys_raw_spu_create(id=*0x%x, attr=*0x%x)", id, attr);
// TODO: check number set by sys_spu_initialize() auto& limits = g_fxo->get<spu_limits_t>();
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.raw_spu = 1}))
{
return CELL_EAGAIN;
}
if (!spu_thread::g_raw_spu_ctr.try_inc(5)) if (!spu_thread::g_raw_spu_ctr.try_inc(5))
{ {
@ -1867,7 +1949,14 @@ error_code sys_isolated_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<voi
return CELL_EAUTHFAIL; return CELL_EAUTHFAIL;
} }
// TODO: check number set by sys_spu_initialize() auto& limits = g_fxo->get<spu_limits_t>();
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.raw_spu = 1}))
{
return CELL_EAGAIN;
}
if (!spu_thread::g_raw_spu_ctr.try_inc(5)) if (!spu_thread::g_raw_spu_ctr.try_inc(5))
{ {