Skip to content

Commit

Permalink
acpica: Extract _OSC parsing to a common file
Browse files Browse the repository at this point in the history
This will be used by pci_host_generic_acpi.c so needs to be in a
common location.

Reviewed by:	imp, jhb
Sponsored by:	Arm Ltd
Differential Revision:	https://reviews.freebsd.org/D48044
  • Loading branch information
zxombie committed Dec 12, 2024
1 parent 938e4b1 commit ba19049
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 58 deletions.
59 changes: 59 additions & 0 deletions sys/dev/acpica/acpi_pcib.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpi_pcibvar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include "pcib_if.h"

Expand Down Expand Up @@ -277,3 +278,61 @@ acpi_pcib_get_cpus(device_t pcib, device_t dev, enum cpu_sets op,

return (bus_get_cpus(pcib, op, setsize, cpuset));
}

int
acpi_pcib_osc(device_t pcib, uint32_t *ap_osc_ctl, uint32_t osc_ctl)
{
ACPI_STATUS status;
ACPI_HANDLE handle;
uint32_t cap_set[3];

static uint8_t pci_host_bridge_uuid[ACPI_UUID_LENGTH] = {
0x5b, 0x4d, 0xdb, 0x33, 0xf7, 0x1f, 0x1c, 0x40,
0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66
};

/*
* Don't invoke _OSC if a control is already granted.
* However, always invoke _OSC during attach when 0 is passed.
*/
if (osc_ctl != 0 && (*ap_osc_ctl & osc_ctl) == osc_ctl)
return (0);

/* Support Field: Extended PCI Config Space, PCI Segment Groups, MSI */
cap_set[PCI_OSC_SUPPORT] = PCIM_OSC_SUPPORT_EXT_PCI_CONF |
PCIM_OSC_SUPPORT_SEG_GROUP | PCIM_OSC_SUPPORT_MSI;
/* Active State Power Management, Clock Power Management Capability */
if (pci_enable_aspm)
cap_set[PCI_OSC_SUPPORT] |= PCIM_OSC_SUPPORT_ASPM |
PCIM_OSC_SUPPORT_CPMC;

/* Control Field */
cap_set[PCI_OSC_CTL] = *ap_osc_ctl | osc_ctl;

handle = acpi_get_handle(pcib);
status = acpi_EvaluateOSC(handle, pci_host_bridge_uuid, 1,
nitems(cap_set), cap_set, cap_set, false);
if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
*ap_osc_ctl |= osc_ctl;
return (0);
}
device_printf(pcib, "_OSC failed: %s\n",
AcpiFormatException(status));
return (EIO);
}

/*
* _OSC may return an error in the status word, but will
* update the control mask always. _OSC should not revoke
* previously-granted controls.
*/
if ((cap_set[PCI_OSC_CTL] & *ap_osc_ctl) != *ap_osc_ctl)
device_printf(pcib, "_OSC revoked %#x\n",
(cap_set[PCI_OSC_CTL] & *ap_osc_ctl) ^ *ap_osc_ctl);
*ap_osc_ctl = cap_set[PCI_OSC_CTL];
if ((*ap_osc_ctl & osc_ctl) != osc_ctl)
return (EIO);

return (0);
}
60 changes: 2 additions & 58 deletions sys/dev/acpica/acpi_pcib_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,62 +286,6 @@ get_decoded_bus_range(struct acpi_hpcib_softc *sc, rman_res_t *startp,
return (true);
}

static int
acpi_pcib_osc(struct acpi_hpcib_softc *sc, uint32_t osc_ctl)
{
ACPI_STATUS status;
uint32_t cap_set[3];

static uint8_t pci_host_bridge_uuid[ACPI_UUID_LENGTH] = {
0x5b, 0x4d, 0xdb, 0x33, 0xf7, 0x1f, 0x1c, 0x40,
0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66
};

/*
* Don't invoke _OSC if a control is already granted.
* However, always invoke _OSC during attach when 0 is passed.
*/
if (osc_ctl != 0 && (sc->ap_osc_ctl & osc_ctl) == osc_ctl)
return (0);

/* Support Field: Extended PCI Config Space, PCI Segment Groups, MSI */
cap_set[PCI_OSC_SUPPORT] = PCIM_OSC_SUPPORT_EXT_PCI_CONF |
PCIM_OSC_SUPPORT_SEG_GROUP | PCIM_OSC_SUPPORT_MSI;
/* Active State Power Management, Clock Power Management Capability */
if (pci_enable_aspm)
cap_set[PCI_OSC_SUPPORT] |= PCIM_OSC_SUPPORT_ASPM |
PCIM_OSC_SUPPORT_CPMC;

/* Control Field */
cap_set[PCI_OSC_CTL] = sc->ap_osc_ctl | osc_ctl;

status = acpi_EvaluateOSC(sc->ap_handle, pci_host_bridge_uuid, 1,
nitems(cap_set), cap_set, cap_set, false);
if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
sc->ap_osc_ctl |= osc_ctl;
return (0);
}
device_printf(sc->ap_dev, "_OSC failed: %s\n",
AcpiFormatException(status));
return (EIO);
}

/*
* _OSC may return an error in the status word, but will
* update the control mask always. _OSC should not revoke
* previously-granted controls.
*/
if ((cap_set[PCI_OSC_CTL] & sc->ap_osc_ctl) != sc->ap_osc_ctl)
device_printf(sc->ap_dev, "_OSC revoked %#x\n",
(cap_set[PCI_OSC_CTL] & sc->ap_osc_ctl) ^ sc->ap_osc_ctl);
sc->ap_osc_ctl = cap_set[PCI_OSC_CTL];
if ((sc->ap_osc_ctl & osc_ctl) != osc_ctl)
return (EIO);

return (0);
}

static int
acpi_pcib_acpi_attach(device_t dev)
{
Expand All @@ -367,7 +311,7 @@ acpi_pcib_acpi_attach(device_t dev)
if (!acpi_DeviceIsPresent(dev))
return (ENXIO);

acpi_pcib_osc(sc, 0);
acpi_pcib_osc(dev, &sc->ap_osc_ctl, 0);

/*
* Get our segment number by evaluating _SEG.
Expand Down Expand Up @@ -759,7 +703,7 @@ acpi_pcib_request_feature(device_t pcib, device_t dev, enum pci_feature feature)
return (EINVAL);
}

return (acpi_pcib_osc(sc, osc_ctl));
return (acpi_pcib_osc(dev, &sc->ap_osc_ctl, osc_ctl));
}

static bus_dma_tag_t
Expand Down
1 change: 1 addition & 0 deletions sys/dev/acpica/acpi_pcibvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
ACPI_BUFFER *prtbuf);
int acpi_pcib_power_for_sleep(device_t pcib, device_t dev,
int *pstate);
int acpi_pcib_osc(device_t pcib, uint32_t *ap_osc_ctl, uint32_t osc_ctl);

#endif /* _KERNEL */

Expand Down

0 comments on commit ba19049

Please sign in to comment.