1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
/*
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/ByteReader.h>
#include <Kernel/Arch/x86/IO.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)
: HostBridge(domain)
, 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);
return *((volatile u8*)(get_device_configuration_memory_mapped_space(bus, device, function).get() + (field & 0xfff)));
}
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);
*((volatile u8*)(get_device_configuration_memory_mapped_space(bus, device, function).get() + (field & 0xfff))) = value;
}
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);
auto region_or_error = MM.allocate_kernel_region(bus_base_address, memory_range_per_bus, "PCI ECAM", Memory::Region::Access::ReadWrite);
// 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));
}
}
|