From c4f5ebc3df8cf3a00bb1b31cf5908c984272a0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 21 Mar 2020 20:11:29 +0100 Subject: [PATCH] PCI: add set_powerstate and get_powerstate hooks Change-Id: I8e32b5fccba3461cdb1b0c6e81b15705b2be1c57 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2447 Reviewed-by: Adrien Destugues --- headers/os/drivers/bus/PCI.h | 2 ++ src/add-ons/kernel/bus_managers/pci/pci.cpp | 31 +++++++++++++++++++ src/add-ons/kernel/bus_managers/pci/pci.h | 3 ++ .../kernel/bus_managers/pci/pci_device.cpp | 18 ++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/headers/os/drivers/bus/PCI.h b/headers/os/drivers/bus/PCI.h index 6a7f42721b..a57f2ab41e 100644 --- a/headers/os/drivers/bus/PCI.h +++ b/headers/os/drivers/bus/PCI.h @@ -36,6 +36,8 @@ typedef struct pci_device_module_info { void (*get_pci_info)(pci_device *device, struct pci_info *info); status_t (*find_pci_extended_capability)(pci_device *device, uint16 capID, uint16 *offset); + uint8 (*get_powerstate)(pci_device *device); + void (*set_powerstate)(pci_device *device, uint8 state); } pci_device_module_info; diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index 04f0ac4012..61b0d0a6b7 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -1801,3 +1801,34 @@ PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function, return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue); } + + +uint8 +PCI::GetPowerstate(PCIDev *device) +{ + uint8 capabilityOffset; + status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); + if (res == B_OK) { + uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); + return (state & PCI_pm_mask); + } + return PCI_pm_state_d0; +} + + +void +PCI::SetPowerstate(PCIDev *device, uint8 newState) +{ + uint8 capabilityOffset; + status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); + if (res == B_OK) { + uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); + if ((state & PCI_pm_mask) != newState) { + WriteConfig(device, capabilityOffset + PCI_pm_status, 2, + (state & ~PCI_pm_mask) | newState); + if ((state & PCI_pm_mask) == PCI_pm_state_d3) + snooze(10); + } + } +} + diff --git a/src/add-ons/kernel/bus_managers/pci/pci.h b/src/add-ons/kernel/bus_managers/pci/pci.h index 948e2d76f2..6b4d1a84d6 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.h +++ b/src/add-ons/kernel/bus_managers/pci/pci.h @@ -114,6 +114,9 @@ public: void ClearDeviceStatus(PCIBus *bus, bool dumpStatus); + uint8 GetPowerstate(PCIDev *device); + void SetPowerstate(PCIDev *device, uint8 state); + void RefreshDeviceInfo(); status_t UpdateInterruptLine(uint8 domain, uint8 bus, diff --git a/src/add-ons/kernel/bus_managers/pci/pci_device.cpp b/src/add-ons/kernel/bus_managers/pci/pci_device.cpp index 359c18ee2d..51aedde16e 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_device.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci_device.cpp @@ -102,6 +102,20 @@ pci_device_find_extended_capability(pci_device* device, uint16 capID, } +static uint8 +pci_device_get_powerstate(pci_device *device) +{ + return gPCI->GetPowerstate(device->device); +} + + +static void +pci_device_set_powerstate(pci_device *device, uint8 state) +{ + return gPCI->SetPowerstate(device->device, state); +} + + static void pci_device_get_pci_info(pci_device* device, struct pci_info* info) { @@ -196,5 +210,7 @@ pci_device_module_info gPCIDeviceModule = { pci_device_write_pci_config, pci_device_find_capability, pci_device_get_pci_info, - pci_device_find_extended_capability + pci_device_find_extended_capability, + pci_device_get_powerstate, + pci_device_set_powerstate };