Serenity Operating System
1/*
2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/ByteReader.h>
8#include <Kernel/Bus/PCI/API.h>
9#include <Kernel/Bus/PCI/Access.h>
10#include <Kernel/Bus/PCI/Controller/VolumeManagementDevice.h>
11
12namespace Kernel::PCI {
13
14static Atomic<u32> s_vmd_pci_domain_number = 0x10000;
15
16NonnullOwnPtr<VolumeManagementDevice> VolumeManagementDevice::must_create(PCI::DeviceIdentifier const& device_identifier)
17{
18 SpinlockLocker locker(device_identifier.operation_lock());
19 u8 start_bus = 0;
20 switch ((PCI::read16_locked(device_identifier, static_cast<PCI::RegisterOffset>(0x44)) >> 8) & 0x3) {
21 case 0:
22 break;
23 case 1:
24 start_bus = 128;
25 break;
26 case 2:
27 start_bus = 224;
28 break;
29 default:
30 dbgln("VMD @ {}: Unknown bus offset option was set to {}", device_identifier.address(),
31 ((PCI::read16_locked(device_identifier, static_cast<PCI::RegisterOffset>(0x44)) >> 8) & 0x3));
32 VERIFY_NOT_REACHED();
33 }
34
35 // FIXME: The end bus might not be 255, so we actually need to check it with the
36 // resource size of BAR0.
37 dbgln("VMD Host bridge @ {}: Start bus at {}, end bus {}", device_identifier.address(), start_bus, 0xff);
38 PCI::Domain domain { s_vmd_pci_domain_number++, start_bus, 0xff };
39 auto start_address = PhysicalAddress(PCI::get_BAR0(device_identifier)).page_base();
40 return adopt_own_if_nonnull(new (nothrow) VolumeManagementDevice(domain, start_address)).release_nonnull();
41}
42
43void VolumeManagementDevice::write8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u8 value)
44{
45 SpinlockLocker locker(m_config_lock);
46 // Note: We must write then read to ensure completion before returning.
47 MemoryBackedHostBridge::write8_field(bus, device, function, field, value);
48 MemoryBackedHostBridge::read8_field(bus, device, function, field);
49}
50void VolumeManagementDevice::write16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u16 value)
51{
52 SpinlockLocker locker(m_config_lock);
53 // Note: We must write then read to ensure completion before returning.
54 MemoryBackedHostBridge::write16_field(bus, device, function, field, value);
55 MemoryBackedHostBridge::read16_field(bus, device, function, field);
56}
57void VolumeManagementDevice::write32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u32 value)
58{
59 SpinlockLocker locker(m_config_lock);
60 // Note: We must write then read to ensure completion before returning.
61 MemoryBackedHostBridge::write32_field(bus, device, function, field, value);
62 MemoryBackedHostBridge::read32_field(bus, device, function, field);
63}
64
65u8 VolumeManagementDevice::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
66{
67 SpinlockLocker locker(m_config_lock);
68 return MemoryBackedHostBridge::read8_field(bus, device, function, field);
69}
70u16 VolumeManagementDevice::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
71{
72 SpinlockLocker locker(m_config_lock);
73 return MemoryBackedHostBridge::read16_field(bus, device, function, field);
74}
75u32 VolumeManagementDevice::read32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field)
76{
77 SpinlockLocker locker(m_config_lock);
78 return MemoryBackedHostBridge::read32_field(bus, device, function, field);
79}
80
81VolumeManagementDevice::VolumeManagementDevice(PCI::Domain const& domain, PhysicalAddress start_address)
82 : MemoryBackedHostBridge(domain, start_address)
83{
84}
85
86}