Native PCI-express HotPlug support.

PCI-express HotPlug support is implemented via bits in the slot
registers of the PCI-express capability of the downstream port along
with an interrupt that triggers when bits in the slot status register
change.

This is implemented for FreeBSD by adding HotPlug support to the
PCI-PCI bridge driver which attaches to the virtual PCI-PCI bridges
representing downstream ports on HotPlug slots. The PCI-PCI bridge
driver registers an interrupt handler to receive HotPlug events. It
also uses the slot registers to determine the current HotPlug state
and drive an internal HotPlug state machine. For simplicty of
implementation, the PCI-PCI bridge device detaches and deletes the
child PCI device when a card is removed from a slot and creates and
attaches a PCI child device when a card is inserted into the slot.

The PCI-PCI bridge driver provides a bus_child_present which claims
that child devices are present on HotPlug-capable slots only when a
card is inserted. Rather than requiring a timeout in the RC for
config accesses to not-present children, the pcib_read/write_config
methods fail all requests when a card is not present (or not yet
ready).

These changes include support for various optional HotPlug
capabilities such as a power controller, mechanical latch,
electro-mechanical interlock, indicators, and an attention button.
It also includes support for devices which require waiting for
command completion events before initiating a subsequent HotPlug
command. However, it has only been tested on ExpressCard systems
which support surprise removal and have none of these optional
capabilities.

PCI-express HotPlug support is conditional on the PCI_HP option
which is enabled by default on arm64, x86, and powerpc.

Reviewed by:	adrian, imp, vangyzen (older versions)
Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D6136
This commit is contained in:
John Baldwin 2016-05-05 22:26:23 +00:00
parent 50b5c1f0e6
commit 82cb5c3b5b
11 changed files with 572 additions and 0 deletions

View File

@ -102,6 +102,7 @@ device cpufreq
device acpi
options ACPI_DMAR
device pci
options PCI_HP # PCI-Express native HotPlug
options PCI_IOV # PCI SR-IOV support
# Floppy drives

View File

@ -96,6 +96,7 @@ device vtnet
# Bus drivers
device pci
options PCI_HP # PCI-Express native HotPlug
options PCI_IOV # PCI SR-IOV support
# Ethernet NICs

View File

@ -1411,6 +1411,7 @@ options MSGBUF_SIZE=40960
# PCI bus & PCI options:
#
device pci
options PCI_HP # PCI-Express native HotPlug
options PCI_IOV # PCI SR-IOV support

View File

@ -177,6 +177,7 @@ NO_SYSCTL_DESCR opt_global.h
NSWBUF_MIN opt_swap.h
MBUF_PACKET_ZONE_DISABLE opt_global.h
PANIC_REBOOT_WAIT_TIME opt_panic.h
PCI_HP opt_pci.h
PCI_IOV opt_global.h
PPC_DEBUG opt_ppc.h
PPC_PROBE_CHIPSET opt_ppc.h

View File

@ -29,6 +29,8 @@
__FBSDID("$FreeBSD$");
#include "opt_acpi.h"
#include "opt_pci.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
@ -312,6 +314,11 @@ acpi_pcib_osc(struct acpi_hpcib_softc *sc)
/* Control Field */
cap_set[2] = 0;
#ifdef PCI_HP
/* Control Field: PCI Express Native Hot Plug */
cap_set[2] |= 0x1;
#endif
status = acpi_EvaluateOSC(sc->ap_handle, pci_host_bridge_uuid, 1,
nitems(cap_set), cap_set, cap_set, false);
if (ACPI_FAILURE(status)) {

View File

@ -35,6 +35,8 @@ __FBSDID("$FreeBSD$");
* PCI:PCI bridge support.
*/
#include "opt_pci.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
@ -43,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
@ -67,6 +70,11 @@ static int pcib_try_enable_ari(device_t pcib, device_t dev);
static int pcib_ari_enabled(device_t pcib);
static void pcib_ari_decode_rid(device_t pcib, uint16_t rid,
int *bus, int *slot, int *func);
#ifdef PCI_HP
static void pcib_pcie_ab_timeout(void *arg);
static void pcib_pcie_cc_timeout(void *arg);
static void pcib_pcie_dll_timeout(void *arg);
#endif
static device_method_t pcib_methods[] = {
/* Device interface */
@ -78,6 +86,7 @@ static device_method_t pcib_methods[] = {
DEVMETHOD(device_resume, pcib_resume),
/* Bus interface */
DEVMETHOD(bus_child_present, pcib_child_present),
DEVMETHOD(bus_read_ivar, pcib_read_ivar),
DEVMETHOD(bus_write_ivar, pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, pcib_alloc_resource),
@ -839,6 +848,466 @@ pcib_set_mem_decode(struct pcib_softc *sc)
}
#endif
#ifdef PCI_HP
/*
* PCI-express HotPlug support.
*/
static void
pcib_probe_hotplug(struct pcib_softc *sc)
{
device_t dev;
dev = sc->dev;
if (pci_find_cap(dev, PCIY_EXPRESS, NULL) != 0)
return;
if (!(pcie_read_config(dev, PCIER_FLAGS, 2) & PCIEM_FLAGS_SLOT))
return;
sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4);
sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_CAP, 4);
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC)
sc->flags |= PCIB_HOTPLUG;
}
/*
* Send a HotPlug command to the slot control register. If this slot
* uses command completion interrupts, these updates will be buffered
* while a previous command is completing.
*/
static void
pcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask)
{
device_t dev;
uint16_t ctl, new;
dev = sc->dev;
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) {
ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
new = (ctl & ~mask) | val;
if (new != ctl)
pcie_write_config(dev, PCIER_SLOT_CTL, new, 2);
return;
}
if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) {
sc->pcie_pending_link_ctl_val &= ~mask;
sc->pcie_pending_link_ctl_val |= val;
sc->pcie_pending_link_ctl_mask |= mask;
} else {
ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
new = (ctl & ~mask) | val;
if (new != ctl) {
pcie_write_config(dev, PCIER_SLOT_CTL, ctl, 2);
sc->flags |= PCIB_HOTPLUG_CMD_PENDING;
if (!cold)
callout_reset(&sc->pcie_cc_timer, hz,
pcib_pcie_cc_timeout, sc);
}
}
}
static void
pcib_pcie_hotplug_command_completed(struct pcib_softc *sc)
{
device_t dev;
uint16_t ctl, new;
dev = sc->dev;
if (bootverbose)
device_printf(dev, "Command Completed\n");
if (!(sc->flags & PCIB_HOTPLUG_CMD_PENDING))
return;
if (sc->pcie_pending_link_ctl_mask != 0) {
ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
new = ctl & ~sc->pcie_pending_link_ctl_mask;
new |= sc->pcie_pending_link_ctl_val;
if (new != ctl) {
pcie_write_config(dev, PCIER_SLOT_CTL, ctl, 2);
if (!cold)
callout_reset(&sc->pcie_cc_timer, hz,
pcib_pcie_cc_timeout, sc);
} else
sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
sc->pcie_pending_link_ctl_mask = 0;
sc->pcie_pending_link_ctl_val = 0;
} else {
callout_stop(&sc->pcie_cc_timer);
sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
}
}
/*
* Returns true if a card is fully inserted from the user's
* perspective. It may not yet be ready for access, but the driver
* can now start enabling access if necessary.
*/
static bool
pcib_hotplug_inserted(struct pcib_softc *sc)
{
/* Pretend the card isn't present if a detach is forced. */
if (sc->flags & PCIB_DETACHING)
return (false);
/* Card must be present in the slot. */
if ((sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS) == 0)
return (false);
/* A power fault implicitly turns off power to the slot. */
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD)
return (false);
/* If the MRL is disengaged, the slot is powered off. */
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP &&
(sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS) != 0)
return (false);
return (true);
}
/*
* Returns -1 if the card is fully inserted, powered, and ready for
* access. Otherwise, returns 0.
*/
static int
pcib_hotplug_present(struct pcib_softc *sc)
{
device_t dev;
dev = sc->dev;
/* Card must be inserted. */
if (!pcib_hotplug_inserted(sc))
return (0);
/*
* Require the Electromechanical Interlock to be engaged if
* present.
*/
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP &&
(sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) == 0)
return (0);
/* Require the Data Link Layer to be active. */
if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) {
if (!(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE))
return (0);
}
return (-1);
}
static void
pcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask,
bool schedule_task)
{
bool card_inserted;
/* Clear DETACHING if Present Detect has cleared. */
if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) ==
PCIEM_SLOT_STA_PDC)
sc->flags &= ~PCIB_DETACHING;
card_inserted = pcib_hotplug_inserted(sc);
/* Turn the power indicator on if a card is inserted. */
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PIP) {
mask |= PCIEM_SLOT_CTL_PIC;
if (card_inserted)
val |= PCIEM_SLOT_CTL_PI_ON;
else if (sc->flags & PCIB_DETACH_PENDING)
val |= PCIEM_SLOT_CTL_PI_BLINK;
else
val |= PCIEM_SLOT_CTL_PI_OFF;
}
/* Turn the power on via the Power Controller if a card is inserted. */
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP) {
mask |= PCIEM_SLOT_CTL_PCC;
if (card_inserted)
val |= PCIEM_SLOT_CTL_PC_ON;
else
val |= PCIEM_SLOT_CTL_PC_OFF;
}
/*
* If a card is inserted, enable the Electromechanical
* Interlock. If a card is not inserted (or we are in the
* process of detaching), disable the Electromechanical
* Interlock.
*/
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP) {
if (card_inserted !=
!(sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS)) {
mask |= PCIEM_SLOT_CTL_EIC;
val |= PCIEM_SLOT_CTL_EIC;
}
}
/*
* Start a timer to see if the Data Link Layer times out.
* Note that we only start the timer if Presence Detect
* changed on this interrupt. Stop any scheduled timer if
* the Data Link Layer is active.
*/
if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) {
if (card_inserted &&
!(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) &&
sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) {
if (cold)
device_printf(sc->dev,
"Data Link Layer inactive\n");
else
callout_reset(&sc->pcie_dll_timer, hz,
pcib_pcie_dll_timeout, sc);
} else if (sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE)
callout_stop(&sc->pcie_dll_timer);
}
pcib_pcie_hotplug_command(sc, val, mask);
/*
* During attach the child "pci" device is added sychronously;
* otherwise, the task is scheduled to manage the child
* device.
*/
if (schedule_task &&
(pcib_hotplug_present(sc) != 0) != (sc->child != NULL))
taskqueue_enqueue(taskqueue_thread, &sc->pcie_hp_task);
}
static void
pcib_pcie_intr(void *arg)
{
struct pcib_softc *sc;
device_t dev;
sc = arg;
dev = sc->dev;
sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
/* Clear the events just reported. */
pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2);
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_ABP) {
if (sc->flags & PCIB_DETACH_PENDING) {
device_printf(dev,
"Attention Button Pressed: Detach Cancelled\n");
sc->flags &= ~PCIB_DETACH_PENDING;
callout_stop(&sc->pcie_ab_timer);
} else {
device_printf(dev,
"Attention Button Pressed: Detaching in 5 seconds\n");
sc->flags |= PCIB_DETACH_PENDING;
callout_reset(&sc->pcie_ab_timer, 5 * hz,
pcib_pcie_ab_timeout, sc);
}
}
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD)
device_printf(dev, "Power Fault Detected\n");
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSC)
device_printf(dev, "MRL Sensor Changed to %s\n",
sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" :
"closed");
if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC)
device_printf(dev, "Present Detect Changed to %s\n",
sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" :
"empty");
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC)
pcib_pcie_hotplug_command_completed(sc);
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_DLLSC) {
sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
if (bootverbose)
device_printf(dev,
"Data Link Layer State Changed to %s\n",
sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE ?
"active" : "inactive");
}
pcib_pcie_hotplug_update(sc, 0, 0, true);
}
static void
pcib_pcie_hotplug_task(void *context, int pending)
{
struct pcib_softc *sc;
device_t dev;
sc = context;
mtx_lock(&Giant);
dev = sc->dev;
if (pcib_hotplug_present(sc) != 0) {
if (sc->child == NULL) {
sc->child = device_add_child(dev, "pci", -1);
bus_generic_attach(dev);
}
} else {
if (sc->child != NULL) {
if (device_delete_child(dev, sc->child) == 0)
sc->child = NULL;
}
}
mtx_unlock(&Giant);
}
static void
pcib_pcie_ab_timeout(void *arg)
{
struct pcib_softc *sc;
device_t dev;
sc = arg;
dev = sc->dev;
mtx_assert(&Giant, MA_OWNED);
if (sc->flags & PCIB_DETACH_PENDING) {
sc->flags |= PCIB_DETACHING;
sc->flags &= ~PCIB_DETACH_PENDING;
pcib_pcie_hotplug_update(sc, 0, 0, true);
}
}
static void
pcib_pcie_cc_timeout(void *arg)
{
struct pcib_softc *sc;
device_t dev;
sc = arg;
dev = sc->dev;
mtx_assert(&Giant, MA_OWNED);
if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) {
device_printf(dev,
"Hotplug Command Timed Out - forcing detach\n");
sc->flags &= ~(PCIB_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING);
sc->flags |= PCIB_DETACHING;
pcib_pcie_hotplug_update(sc, 0, 0, true);
}
}
static void
pcib_pcie_dll_timeout(void *arg)
{
struct pcib_softc *sc;
device_t dev;
uint16_t sta;
sc = arg;
dev = sc->dev;
mtx_assert(&Giant, MA_OWNED);
sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
if (!(sta & PCIEM_LINK_STA_DL_ACTIVE)) {
device_printf(dev,
"Timed out waiting for Data Link Layer Active\n");
sc->flags |= PCIB_DETACHING;
pcib_pcie_hotplug_update(sc, 0, 0, true);
} else if (sta != sc->pcie_link_sta) {
device_printf(dev,
"Missed HotPlug interrupt waiting for DLL Active\n");
pcib_pcie_intr(sc);
}
}
static int
pcib_alloc_pcie_irq(struct pcib_softc *sc)
{
device_t dev;
int count, error, rid;
rid = -1;
dev = sc->dev;
/*
* For simplicity, only use MSI-X if there is a single message.
* To support a device with multiple messages we would have to
* use remap intr if the MSI number is not 0.
*/
count = pci_msix_count(dev);
if (count == 1) {
error = pci_alloc_msix(dev, &count);
if (error == 0)
rid = 1;
}
if (rid < 0 && pci_msi_count(dev) > 0) {
count = 1;
error = pci_alloc_msi(dev, &count);
if (error == 0)
rid = 1;
}
if (rid < 0)
rid = 0;
sc->pcie_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
if (sc->pcie_irq == NULL) {
device_printf(dev,
"Failed to allocate interrupt for PCI-e events\n");
if (rid > 0)
pci_release_msi(dev);
return (ENXIO);
}
error = bus_setup_intr(dev, sc->pcie_irq, INTR_TYPE_MISC,
NULL, pcib_pcie_intr, sc, &sc->pcie_ihand);
if (error) {
device_printf(dev, "Failed to setup PCI-e interrupt handler\n");
bus_release_resource(dev, SYS_RES_IRQ, rid, sc->pcie_irq);
if (rid > 0)
pci_release_msi(dev);
return (error);
}
return (0);
}
static void
pcib_setup_hotplug(struct pcib_softc *sc)
{
device_t dev;
uint16_t mask, val;
dev = sc->dev;
callout_init(&sc->pcie_ab_timer, 0);
callout_init(&sc->pcie_cc_timer, 0);
callout_init(&sc->pcie_dll_timer, 0);
TASK_INIT(&sc->pcie_hp_task, 0, pcib_pcie_hotplug_task, sc);
/* Allocate IRQ. */
if (pcib_alloc_pcie_irq(sc) != 0)
return;
sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
/* Enable HotPlug events. */
mask = PCIEM_SLOT_CTL_DLLSCE | PCIEM_SLOT_CTL_HPIE |
PCIEM_SLOT_CTL_CCIE | PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE |
PCIEM_SLOT_CTL_PFDE | PCIEM_SLOT_CTL_ABPE;
val = PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_HPIE;
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_APB)
val |= PCIEM_SLOT_CTL_ABPE;
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP)
val |= PCIEM_SLOT_CTL_PFDE;
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP)
val |= PCIEM_SLOT_CTL_MRLSCE;
if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS))
val |= PCIEM_SLOT_CTL_CCIE;
if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE)
val |= PCIEM_SLOT_CTL_DLLSCE;
/* Turn the attention indicator off. */
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_AIP) {
mask |= PCIEM_SLOT_CTL_AIC;
val |= PCIEM_SLOT_CTL_AI_OFF;
}
pcib_pcie_hotplug_update(sc, val, mask, false);
}
#endif
/*
* Get current bridge configuration.
*/
@ -1017,11 +1486,18 @@ pcib_attach_common(device_t dev)
pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
sc->flags |= PCIB_SUBTRACTIVE;
#ifdef PCI_HP
pcib_probe_hotplug(sc);
#endif
#ifdef NEW_PCIB
#ifdef PCI_RES_BUS
pcib_setup_secbus(dev, &sc->bus, 1);
#endif
pcib_probe_windows(sc);
#endif
#ifdef PCI_HP
if (sc->flags & PCIB_HOTPLUG)
pcib_setup_hotplug(sc);
#endif
if (bootverbose) {
device_printf(dev, " domain %d\n", sc->domain);
@ -1074,6 +1550,17 @@ pcib_attach_common(device_t dev)
pci_enable_busmaster(dev);
}
#ifdef PCI_HP
static int
pcib_present(struct pcib_softc *sc)
{
if (sc->flags & PCIB_HOTPLUG)
return (pcib_hotplug_present(sc) != 0);
return (1);
}
#endif
int
pcib_attach_child(device_t dev)
{
@ -1085,6 +1572,13 @@ pcib_attach_child(device_t dev)
return(0);
}
#ifdef PCI_HP
if (!pcib_present(sc)) {
/* An empty HotPlug slot, so don't add a PCI bus yet. */
return (0);
}
#endif
sc->child = device_add_child(dev, "pci", -1);
return (bus_generic_attach(dev));
}
@ -1128,6 +1622,22 @@ pcib_bridge_init(device_t dev)
pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4);
}
int
pcib_child_present(device_t dev, device_t child)
{
#ifdef PCI_HP
struct pcib_softc *sc = device_get_softc(dev);
int retval;
retval = bus_child_present(dev);
if (retval != 0 && sc->flags & PCIB_HOTPLUG)
retval = pcib_hotplug_present(sc);
return (retval);
#else
return (bus_child_present(dev));
#endif
}
int
pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
@ -1909,7 +2419,21 @@ pcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot,
static uint32_t
pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
{
#ifdef PCI_HP
struct pcib_softc *sc;
sc = device_get_softc(dev);
if (!pcib_present(sc)) {
switch (width) {
case 2:
return (0xffff);
case 1:
return (0xff);
default:
return (0xffffffff);
}
}
#endif
pcib_xlate_ari(dev, b, &s, &f);
return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s,
f, reg, width));
@ -1918,7 +2442,13 @@ pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
static void
pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
{
#ifdef PCI_HP
struct pcib_softc *sc;
sc = device_get_softc(dev);
if (!pcib_present(sc))
return;
#endif
pcib_xlate_ari(dev, b, &s, &f);
PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f,
reg, val, width);

View File

@ -33,6 +33,9 @@
#ifndef __PCIB_PRIVATE_H__
#define __PCIB_PRIVATE_H__
#include <sys/_callout.h>
#include <sys/_task.h>
#ifdef NEW_PCIB
/*
* Data structure and routines that Host to PCI bridge drivers can use
@ -107,6 +110,10 @@ struct pcib_softc
#define PCIB_DISABLE_MSI 0x2
#define PCIB_DISABLE_MSIX 0x4
#define PCIB_ENABLE_ARI 0x8
#define PCIB_HOTPLUG 0x10
#define PCIB_HOTPLUG_CMD_PENDING 0x20
#define PCIB_DETACH_PENDING 0x40
#define PCIB_DETACHING 0x80
u_int domain; /* domain number */
u_int pribus; /* primary bus number */
struct pcib_secbus bus; /* secondary bus numbers */
@ -123,6 +130,18 @@ struct pcib_softc
uint32_t iolimit; /* topmost address of port window */
#endif
uint16_t bridgectl; /* bridge control register */
uint16_t pcie_link_sta;
uint16_t pcie_slot_sta;
uint32_t pcie_link_cap;
uint32_t pcie_slot_cap;
uint16_t pcie_pending_link_ctl_mask;
uint16_t pcie_pending_link_ctl_val;
struct resource *pcie_irq;
void *pcie_ihand;
struct task pcie_hp_task;
struct callout pcie_ab_timer;
struct callout pcie_cc_timer;
struct callout pcie_dll_timer;
};
#define PCIB_SUPPORTED_ARI_VER 1
@ -151,6 +170,7 @@ void pcib_bridge_init(device_t dev);
#ifdef NEW_PCIB
const char *pcib_child_name(device_t child);
#endif
int pcib_child_present(device_t dev, device_t child);
int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,

View File

@ -850,8 +850,16 @@
#define PCIEM_SLOT_CTL_CCIE 0x0010
#define PCIEM_SLOT_CTL_HPIE 0x0020
#define PCIEM_SLOT_CTL_AIC 0x00c0
#define PCIEM_SLOT_CTL_AI_ON 0x0040
#define PCIEM_SLOT_CTL_AI_BLINK 0x0080
#define PCIEM_SLOT_CTL_AI_OFF 0x00c0
#define PCIEM_SLOT_CTL_PIC 0x0300
#define PCIEM_SLOT_CTL_PI_ON 0x0100
#define PCIEM_SLOT_CTL_PI_BLINK 0x0200
#define PCIEM_SLOT_CTL_PI_OFF 0x0300
#define PCIEM_SLOT_CTL_PCC 0x0400
#define PCIEM_SLOT_CTL_PC_ON 0x0000
#define PCIEM_SLOT_CTL_PC_OFF 0x0400
#define PCIEM_SLOT_CTL_EIC 0x0800
#define PCIEM_SLOT_CTL_DLLSCE 0x1000
#define PCIER_SLOT_STA 0x1a

View File

@ -101,6 +101,7 @@ device cpufreq
# Bus support.
device acpi
device pci
options PCI_HP # PCI-Express native HotPlug
options PCI_IOV # PCI SR-IOV support
# Floppy drives

View File

@ -102,6 +102,7 @@ device cpufreq
# Standard busses
device pci
options PCI_HP # PCI-Express native HotPlug
device agp
# ATA controllers

View File

@ -99,6 +99,7 @@ device cpufreq
# Standard busses
device pci
options PCI_HP # PCI-Express native HotPlug
device agp
# ATA controllers