2022-01-07 09:10:44 -03:00
/*
* Copyright ( c ) 2022 , Liav A . < liavalb @ hotmail . co . il >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <AK/ByteReader.h>
# include <Kernel/Bus/PCI/Access.h>
# include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h>
namespace Kernel : : PCI {
NonnullOwnPtr < MemoryBackedHostBridge > MemoryBackedHostBridge : : must_create ( Domain const & domain , PhysicalAddress start_address )
{
return adopt_own_if_nonnull ( new ( nothrow ) MemoryBackedHostBridge ( domain , start_address ) ) . release_nonnull ( ) ;
}
MemoryBackedHostBridge : : MemoryBackedHostBridge ( PCI : : Domain const & domain , PhysicalAddress start_address )
2022-09-02 07:41:48 -03:00
: HostController ( domain )
2022-01-07 09:10:44 -03:00
, m_start_address ( start_address )
{
}
u8 MemoryBackedHostBridge : : read8_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < = 0xfff ) ;
2022-04-01 14:58:27 -03:00
return * ( ( u8 volatile * ) ( get_device_configuration_memory_mapped_space ( bus , device , function ) . get ( ) + ( field & 0xfff ) ) ) ;
2022-01-07 09:10:44 -03:00
}
u16 MemoryBackedHostBridge : : read16_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < 0xfff ) ;
u16 data = 0 ;
ByteReader : : load < u16 > ( get_device_configuration_memory_mapped_space ( bus , device , function ) . offset ( field & 0xfff ) . as_ptr ( ) , data ) ;
return data ;
}
u32 MemoryBackedHostBridge : : read32_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < = 0xffc ) ;
u32 data = 0 ;
ByteReader : : load < u32 > ( get_device_configuration_memory_mapped_space ( bus , device , function ) . offset ( field & 0xfff ) . as_ptr ( ) , data ) ;
return data ;
}
void MemoryBackedHostBridge : : write8_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field , u8 value )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < = 0xfff ) ;
2022-04-01 14:58:27 -03:00
* ( ( u8 volatile * ) ( get_device_configuration_memory_mapped_space ( bus , device , function ) . get ( ) + ( field & 0xfff ) ) ) = value ;
2022-01-07 09:10:44 -03:00
}
void MemoryBackedHostBridge : : write16_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field , u16 value )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < 0xfff ) ;
ByteReader : : store < u16 > ( get_device_configuration_memory_mapped_space ( bus , device , function ) . offset ( field & 0xfff ) . as_ptr ( ) , value ) ;
}
void MemoryBackedHostBridge : : write32_field ( BusNumber bus , DeviceNumber device , FunctionNumber function , u32 field , u32 value )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
VERIFY ( field < = 0xffc ) ;
ByteReader : : store < u32 > ( get_device_configuration_memory_mapped_space ( bus , device , function ) . offset ( field & 0xfff ) . as_ptr ( ) , value ) ;
}
void MemoryBackedHostBridge : : map_bus_region ( BusNumber bus )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
if ( m_mapped_bus = = bus & & m_mapped_bus_region )
return ;
auto bus_base_address = determine_memory_mapped_bus_base_address ( bus ) ;
2022-07-11 14:32:29 -03:00
auto region_or_error = MM . allocate_kernel_region ( bus_base_address , memory_range_per_bus , " PCI ECAM " sv , Memory : : Region : : Access : : ReadWrite ) ;
2022-01-07 09:10:44 -03:00
// FIXME: Find a way to propagate error from here.
if ( region_or_error . is_error ( ) )
VERIFY_NOT_REACHED ( ) ;
m_mapped_bus_region = region_or_error . release_value ( ) ;
m_mapped_bus = bus ;
dbgln_if ( PCI_DEBUG , " PCI: New PCI ECAM Mapped region for bus {} @ {} {} " , bus , m_mapped_bus_region - > vaddr ( ) , m_mapped_bus_region - > physical_page ( 0 ) - > paddr ( ) ) ;
}
VirtualAddress MemoryBackedHostBridge : : get_device_configuration_memory_mapped_space ( BusNumber bus , DeviceNumber device , FunctionNumber function )
{
VERIFY ( Access : : the ( ) . access_lock ( ) . is_locked ( ) ) ;
map_bus_region ( bus ) ;
return m_mapped_bus_region - > vaddr ( ) . offset ( mmio_device_space_size * function . value ( ) + ( mmio_device_space_size * to_underlying ( Limits : : MaxFunctionsPerDevice ) ) * device . value ( ) ) ;
}
PhysicalAddress MemoryBackedHostBridge : : determine_memory_mapped_bus_base_address ( BusNumber bus ) const
{
auto start_bus = min ( bus . value ( ) , m_domain . start_bus ( ) ) ;
return m_start_address . offset ( memory_range_per_bus * ( bus . value ( ) - start_bus ) ) ;
}
}