ladybird/Kernel/Bus/PCI/API.h

51 lines
2.0 KiB
C
Raw Normal View History

Kernel/PCI: Simplify the entire subsystem A couple of things were changed: 1. Semantic changes - PCI segments are now called PCI domains, to better match what they are really. It's also the name that Linux gave, and it seems that Wikipedia also uses this name. We also remove PCI::ChangeableAddress, because it was used in the past but now it's no longer being used. 2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as they made a bunch of unnecessary complexity. Instead, Windowed access is removed entirely (this was tested, but never was benchmarked), so we are left with IO access and memory access options. The memory access option is essentially mapping the PCI bus (from the chosen PCI domain), to virtual memory as-is. This means that unless needed, at any time, there is only one PCI bus being mapped, and this is changed if access to another PCI bus in the same PCI domain is needed. For now, we don't support mapping of different PCI buses from different PCI domains at the same time, because basically it's still a non-issue for most machines out there. 2. OOM-safety is increased, especially when constructing the Access object. It means that we pre-allocating any needed resources, and we try to find PCI domains (if requested to initialize memory access) after we attempt to construct the Access object, so it's possible to fail at this point "gracefully". 3. All PCI API functions are now separated into a different header file, which means only "clients" of the PCI subsystem API will need to include that header file. 4. Functional changes - we only allow now to enumerate the bus after a hardware scan. This means that the old method "enumerate_hardware" is removed, so, when initializing an Access object, the initializing function must call rescan on it to force it to find devices. This makes it possible to fail rescan, and also to defer it after construction from both OOM-safety terms and hotplug capabilities.
2021-09-07 12:08:38 +03:00
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <AK/Try.h>
Kernel/PCI: Simplify the entire subsystem A couple of things were changed: 1. Semantic changes - PCI segments are now called PCI domains, to better match what they are really. It's also the name that Linux gave, and it seems that Wikipedia also uses this name. We also remove PCI::ChangeableAddress, because it was used in the past but now it's no longer being used. 2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as they made a bunch of unnecessary complexity. Instead, Windowed access is removed entirely (this was tested, but never was benchmarked), so we are left with IO access and memory access options. The memory access option is essentially mapping the PCI bus (from the chosen PCI domain), to virtual memory as-is. This means that unless needed, at any time, there is only one PCI bus being mapped, and this is changed if access to another PCI bus in the same PCI domain is needed. For now, we don't support mapping of different PCI buses from different PCI domains at the same time, because basically it's still a non-issue for most machines out there. 2. OOM-safety is increased, especially when constructing the Access object. It means that we pre-allocating any needed resources, and we try to find PCI domains (if requested to initialize memory access) after we attempt to construct the Access object, so it's possible to fail at this point "gracefully". 3. All PCI API functions are now separated into a different header file, which means only "clients" of the PCI subsystem API will need to include that header file. 4. Functional changes - we only allow now to enumerate the bus after a hardware scan. This means that the old method "enumerate_hardware" is removed, so, when initializing an Access object, the initializing function must call rescan on it to force it to find devices. This makes it possible to fail rescan, and also to defer it after construction from both OOM-safety terms and hotplug capabilities.
2021-09-07 12:08:38 +03:00
#include <Kernel/Bus/PCI/Definitions.h>
namespace Kernel::PCI {
Kernel/PCI: Hold a reference to DeviceIdentifier in the Device class There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
2022-02-10 19:33:13 +03:00
void write8_locked(DeviceIdentifier const&, PCI::RegisterOffset field, u8 value);
void write16_locked(DeviceIdentifier const&, PCI::RegisterOffset field, u16 value);
void write32_locked(DeviceIdentifier const&, PCI::RegisterOffset field, u32 value);
u8 read8_locked(DeviceIdentifier const&, PCI::RegisterOffset field);
u16 read16_locked(DeviceIdentifier const&, PCI::RegisterOffset field);
u32 read32_locked(DeviceIdentifier const&, PCI::RegisterOffset field);
Kernel/PCI: Simplify the entire subsystem A couple of things were changed: 1. Semantic changes - PCI segments are now called PCI domains, to better match what they are really. It's also the name that Linux gave, and it seems that Wikipedia also uses this name. We also remove PCI::ChangeableAddress, because it was used in the past but now it's no longer being used. 2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as they made a bunch of unnecessary complexity. Instead, Windowed access is removed entirely (this was tested, but never was benchmarked), so we are left with IO access and memory access options. The memory access option is essentially mapping the PCI bus (from the chosen PCI domain), to virtual memory as-is. This means that unless needed, at any time, there is only one PCI bus being mapped, and this is changed if access to another PCI bus in the same PCI domain is needed. For now, we don't support mapping of different PCI buses from different PCI domains at the same time, because basically it's still a non-issue for most machines out there. 2. OOM-safety is increased, especially when constructing the Access object. It means that we pre-allocating any needed resources, and we try to find PCI domains (if requested to initialize memory access) after we attempt to construct the Access object, so it's possible to fail at this point "gracefully". 3. All PCI API functions are now separated into a different header file, which means only "clients" of the PCI subsystem API will need to include that header file. 4. Functional changes - we only allow now to enumerate the bus after a hardware scan. This means that the old method "enumerate_hardware" is removed, so, when initializing an Access object, the initializing function must call rescan on it to force it to find devices. This makes it possible to fail rescan, and also to defer it after construction from both OOM-safety terms and hotplug capabilities.
2021-09-07 12:08:38 +03:00
Kernel/PCI: Hold a reference to DeviceIdentifier in the Device class There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
2022-02-10 19:33:13 +03:00
HardwareID get_hardware_id(DeviceIdentifier const&);
bool is_io_space_enabled(DeviceIdentifier const&);
ErrorOr<void> enumerate(Function<void(DeviceIdentifier const&)> callback);
Kernel/PCI: Hold a reference to DeviceIdentifier in the Device class There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
2022-02-10 19:33:13 +03:00
void enable_interrupt_line(DeviceIdentifier const&);
void disable_interrupt_line(DeviceIdentifier const&);
void raw_access(DeviceIdentifier const&, u32, size_t, u32);
u32 get_BAR0(DeviceIdentifier const&);
u32 get_BAR1(DeviceIdentifier const&);
u32 get_BAR2(DeviceIdentifier const&);
u32 get_BAR3(DeviceIdentifier const&);
u32 get_BAR4(DeviceIdentifier const&);
u32 get_BAR5(DeviceIdentifier const&);
u32 get_BAR(DeviceIdentifier const&, HeaderType0BaseRegister);
size_t get_BAR_space_size(DeviceIdentifier const&, HeaderType0BaseRegister);
Kernel: Introduce the IOWindow class This class is intended to replace all IOAddress usages in the Kernel codebase altogether. The idea is to ensure IO can be done in arch-specific manner that is determined mostly in compile-time, but to still be able to use most of the Kernel code in non-x86 builds. Specific devices that rely on x86-specific IO instructions are already placed in the Arch/x86 directory and are omitted for non-x86 builds. The reason this works so well is the fact that x86 IO space acts in a similar fashion to the traditional memory space being available in most CPU architectures - the x86 IO space is essentially just an array of bytes like the physical memory address space, but requires x86 IO instructions to load and store data. Therefore, many devices allow host software to interact with the hardware registers in both ways, with a noticeable trend even in the modern x86 hardware to move away from the old x86 IO space to exclusively using memory-mapped IO. Therefore, the IOWindow class encapsulates both methods for x86 builds. The idea is to allow PCI devices to be used in either way in x86 builds, so when trying to map an IOWindow on a PCI BAR, the Kernel will try to find the proper method being declared with the PCI BAR flags. For old PCI hardware on non-x86 builds this might turn into a problem as we can't use port mapped IO, so the Kernel will gracefully fail with ENOTSUP error code if that's the case, as there's really nothing we can do within such case. For general IO, the read{8,16,32} and write{8,16,32} methods are available as a convenient API for other places in the Kernel. There are simply no direct 64-bit IO API methods yet, as it's not needed right now and is not considered to be Arch-agnostic too - the x86 IO space doesn't support generating 64 bit cycle on IO bus and instead requires two 2 32-bit accesses. If for whatever reason it appears to be necessary to do IO in such manner, it could probably be added with some neat tricks to do so. It is recommended to use Memory::TypedMapping struct if direct 64 bit IO is actually needed.
2022-09-23 11:50:04 +03:00
BARSpaceType get_BAR_space_type(u32 pci_bar_value);
size_t get_expansion_rom_space_size(DeviceIdentifier const&);
Kernel/PCI: Hold a reference to DeviceIdentifier in the Device class There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
2022-02-10 19:33:13 +03:00
void enable_bus_mastering(DeviceIdentifier const&);
void disable_bus_mastering(DeviceIdentifier const&);
void enable_io_space(DeviceIdentifier const&);
void disable_io_space(DeviceIdentifier const&);
void enable_memory_space(DeviceIdentifier const&);
void disable_memory_space(DeviceIdentifier const&);
Kernel/PCI: Simplify the entire subsystem A couple of things were changed: 1. Semantic changes - PCI segments are now called PCI domains, to better match what they are really. It's also the name that Linux gave, and it seems that Wikipedia also uses this name. We also remove PCI::ChangeableAddress, because it was used in the past but now it's no longer being used. 2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as they made a bunch of unnecessary complexity. Instead, Windowed access is removed entirely (this was tested, but never was benchmarked), so we are left with IO access and memory access options. The memory access option is essentially mapping the PCI bus (from the chosen PCI domain), to virtual memory as-is. This means that unless needed, at any time, there is only one PCI bus being mapped, and this is changed if access to another PCI bus in the same PCI domain is needed. For now, we don't support mapping of different PCI buses from different PCI domains at the same time, because basically it's still a non-issue for most machines out there. 2. OOM-safety is increased, especially when constructing the Access object. It means that we pre-allocating any needed resources, and we try to find PCI domains (if requested to initialize memory access) after we attempt to construct the Access object, so it's possible to fail at this point "gracefully". 3. All PCI API functions are now separated into a different header file, which means only "clients" of the PCI subsystem API will need to include that header file. 4. Functional changes - we only allow now to enumerate the bus after a hardware scan. This means that the old method "enumerate_hardware" is removed, so, when initializing an Access object, the initializing function must call rescan on it to force it to find devices. This makes it possible to fail rescan, and also to defer it after construction from both OOM-safety terms and hotplug capabilities.
2021-09-07 12:08:38 +03:00
Kernel/PCI: Hold a reference to DeviceIdentifier in the Device class There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
2022-02-10 19:33:13 +03:00
// FIXME: Remove this once we can use PCI::Capability with inline buffer
// so we don't need this method
DeviceIdentifier const& get_device_identifier(Address address);
Kernel/PCI: Simplify the entire subsystem A couple of things were changed: 1. Semantic changes - PCI segments are now called PCI domains, to better match what they are really. It's also the name that Linux gave, and it seems that Wikipedia also uses this name. We also remove PCI::ChangeableAddress, because it was used in the past but now it's no longer being used. 2. There are no WindowedMMIOAccess or MMIOAccess classes anymore, as they made a bunch of unnecessary complexity. Instead, Windowed access is removed entirely (this was tested, but never was benchmarked), so we are left with IO access and memory access options. The memory access option is essentially mapping the PCI bus (from the chosen PCI domain), to virtual memory as-is. This means that unless needed, at any time, there is only one PCI bus being mapped, and this is changed if access to another PCI bus in the same PCI domain is needed. For now, we don't support mapping of different PCI buses from different PCI domains at the same time, because basically it's still a non-issue for most machines out there. 2. OOM-safety is increased, especially when constructing the Access object. It means that we pre-allocating any needed resources, and we try to find PCI domains (if requested to initialize memory access) after we attempt to construct the Access object, so it's possible to fail at this point "gracefully". 3. All PCI API functions are now separated into a different header file, which means only "clients" of the PCI subsystem API will need to include that header file. 4. Functional changes - we only allow now to enumerate the bus after a hardware scan. This means that the old method "enumerate_hardware" is removed, so, when initializing an Access object, the initializing function must call rescan on it to force it to find devices. This makes it possible to fail rescan, and also to defer it after construction from both OOM-safety terms and hotplug capabilities.
2021-09-07 12:08:38 +03:00
}