Page MenuHomeFreeBSD

D3932.diff
No OneTemporary

D3932.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -2130,6 +2130,7 @@
dev/pci/pci_user.c optional pci
dev/pci/pcib_if.m standard
dev/pci/pcib_support.c standard
+dev/pci/pcie_hp.c optional pci pci_ehp
dev/pci/vga_pci.c optional pci
dev/pcn/if_pcn.c optional pcn pci
dev/pdq/if_fea.c optional fea eisa
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -176,6 +176,7 @@
MBUF_PACKET_ZONE_DISABLE opt_global.h
PANIC_REBOOT_WAIT_TIME opt_panic.h
PCI_IOV opt_global.h
+PCI_EHP opt_pciehp.h
PPC_DEBUG opt_ppc.h
PPC_PROBE_CHIPSET opt_ppc.h
PPS_SYNC opt_ntp.h
Index: sys/dev/acpica/acpi_pci.c
===================================================================
--- sys/dev/acpica/acpi_pci.c
+++ sys/dev/acpica/acpi_pci.c
@@ -83,6 +83,7 @@
int state);
static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child);
+static device_t acpi_pci_add_child_method(device_t, uint8_t, uint8_t);
#ifdef PCI_IOV
static device_t acpi_pci_create_iov_child(device_t bus, device_t pf,
@@ -103,6 +104,7 @@
/* PCI interface */
DEVMETHOD(pci_set_powerstate, acpi_pci_set_powerstate_method),
+ DEVMETHOD(pci_add_child, acpi_pci_add_child_method),
#ifdef PCI_IOV
DEVMETHOD(pci_create_iov_child, acpi_pci_create_iov_child),
#endif
@@ -223,6 +225,14 @@
return (error);
}
+static device_t
+acpi_pci_add_child_method(device_t dev, uint8_t s,
+ uint8_t f)
+{
+
+ return pci_add_child_size(dev, s, f, sizeof(struct acpi_pci_devinfo));
+}
+
static void
acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child)
{
@@ -322,7 +332,7 @@
* pci_add_children() doesn't find. We currently just ignore
* these devices.
*/
- pci_add_children(dev, domain, busno, sizeof(struct acpi_pci_devinfo));
+ pci_add_children(dev);
AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
acpi_pci_save_handle, NULL, dev, NULL);
Index: sys/dev/cardbus/cardbus.c
===================================================================
--- sys/dev/cardbus/cardbus.c
+++ sys/dev/cardbus/cardbus.c
@@ -174,7 +174,8 @@
{
device_t brdev = device_get_parent(cbdev);
device_t child;
- int bus, domain, slot, func;
+ uint32_t domain;
+ uint8_t bus, slot, func;
int cardattached = 0;
int cardbusfunchigh = 0;
struct cardbus_softc *sc;
Index: sys/dev/pci/pci.c
===================================================================
--- sys/dev/pci/pci.c
+++ sys/dev/pci/pci.c
@@ -30,6 +30,7 @@
__FBSDID("$FreeBSD$");
#include "opt_bus.h"
+#include "opt_pciehp.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -120,8 +121,11 @@
u_int irq);
static uint16_t pci_get_rid_method(device_t dev, device_t child);
+static int pci_child_present(device_t, uint8_t, uint8_t, uint8_t);
+static int pci_bus_child_present(device_t dev, device_t child);
+static device_t pci_add_child_method(device_t, uint8_t, uint8_t);
-static struct pci_devinfo * pci_fill_devinfo(device_t pcib, int d, int b, int s,
+static struct pci_devinfo *pci_fill_devinfo(device_t pcib, int d, int b, int s,
int f, uint16_t vid, uint16_t did, size_t size);
static device_method_t pci_methods[] = {
@@ -162,6 +166,7 @@
DEVMETHOD(bus_remap_intr, pci_remap_intr_method),
DEVMETHOD(bus_suspend_child, pci_suspend_child),
DEVMETHOD(bus_resume_child, pci_resume_child),
+ DEVMETHOD(bus_child_present, pci_bus_child_present),
/* PCI interface */
DEVMETHOD(pci_read_config, pci_read_config_method),
@@ -189,6 +194,7 @@
DEVMETHOD(pci_msix_count, pci_msix_count_method),
DEVMETHOD(pci_get_rid, pci_get_rid_method),
DEVMETHOD(pci_child_added, pci_child_added_method),
+ DEVMETHOD(pci_add_child, pci_add_child_method),
#ifdef PCI_IOV
DEVMETHOD(pci_iov_attach, pci_iov_attach_method),
DEVMETHOD(pci_iov_detach, pci_iov_detach_method),
@@ -611,7 +617,8 @@
/* read configuration header into pcicfgregs structure */
struct pci_devinfo *
-pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
+pci_read_device(device_t pcib, uint32_t d, uint8_t b, uint8_t s, uint8_t f,
+ size_t size)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w)
uint16_t vid, did;
@@ -3505,40 +3512,33 @@
#endif
}
-static struct pci_devinfo *
-pci_identify_function(device_t pcib, device_t dev, int domain, int busno,
- int slot, int func, size_t dinfo_size)
-{
- struct pci_devinfo *dinfo;
-
- dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size);
- if (dinfo != NULL)
- pci_add_child(dev, dinfo);
-
- return (dinfo);
-}
-
void
-pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
+pci_add_children(device_t dev)
{
-#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w)
- device_t pcib = device_get_parent(dev);
- struct pci_devinfo *dinfo;
+ device_t pcib, child;
int maxslots;
int s, f, pcifunchigh;
+ uint32_t domain;
+ uint8_t busno;
uint8_t hdrtype;
int first_func;
+ pcib = device_get_parent(dev);
+ domain = pcib_get_domain(dev);
+ busno = pcib_get_bus(dev);
+
/*
* Try to detect a device at slot 0, function 0. If it exists, try to
* enable ARI. We must enable ARI before detecting the rest of the
* functions on this bus as ARI changes the set of slots and functions
* that are legal on this bus.
*/
- dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0,
- dinfo_size);
- if (dinfo != NULL && pci_enable_ari)
- PCIB_TRY_ENABLE_ARI(pcib, dinfo->cfg.dev);
+ if (pci_child_present(pcib, busno, 0, 0) == -1 &&
+ pci_find_dbsf(domain, busno, 0, 0) == NULL) {
+ child = PCI_ADD_CHILD(dev, 0, 0);
+ if (pci_enable_ari)
+ PCIB_TRY_ENABLE_ARI(pcib, child);
+ }
/*
* Start looking for new devices on slot 0 at function 1 because we
@@ -3546,23 +3546,21 @@
*/
first_func = 1;
- KASSERT(dinfo_size >= sizeof(struct pci_devinfo),
- ("dinfo_size too small"));
maxslots = PCIB_MAXSLOTS(pcib);
for (s = 0; s <= maxslots; s++, first_func = 0) {
pcifunchigh = 0;
f = 0;
- DELAY(1);
- hdrtype = REG(PCIR_HDRTYPE, 1);
+ hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1);
if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
continue;
if (hdrtype & PCIM_MFDEV)
pcifunchigh = PCIB_MAXFUNCS(pcib);
- for (f = first_func; f <= pcifunchigh; f++)
- pci_identify_function(pcib, dev, domain, busno, s, f,
- dinfo_size);
+ for (f = first_func; f <= pcifunchigh; f++) {
+ if (pci_child_present(pcib, busno, s, f) == -1 &&
+ pci_find_dbsf(domain, busno, s, f) == NULL)
+ PCI_ADD_CHILD(dev, s, f);
+ }
}
-#undef REG
}
#ifdef PCI_IOV
@@ -3613,6 +3611,7 @@
void
pci_add_child(device_t bus, struct pci_devinfo *dinfo)
{
+
dinfo->cfg.dev = device_add_child(bus, NULL, -1);
device_set_ivars(dinfo->cfg.dev, dinfo);
resource_list_init(&dinfo->resources);
@@ -3629,6 +3628,35 @@
}
+static device_t
+pci_add_child_method(device_t dev, uint8_t s, uint8_t f)
+{
+
+ return pci_add_child_size(dev, s, f, sizeof(struct pci_devinfo));
+}
+
+device_t
+pci_add_child_size(device_t dev, uint8_t s, uint8_t f,
+ size_t dinfo_size)
+{
+ device_t pcib;
+ struct pci_devinfo *dinfo;
+ uint32_t d;
+ uint8_t b;
+
+ pcib = device_get_parent(dev);
+ d = pcib_get_domain(dev);
+ b = pcib_get_bus(dev);
+
+ dinfo = pci_read_device(pcib, d, b, s, f, dinfo_size);
+ if (dinfo == NULL)
+ return NULL;
+
+ pci_add_child(dev, dinfo);
+
+ return dinfo->cfg.dev;
+}
+
static int
pci_probe(device_t dev)
{
@@ -3683,13 +3711,18 @@
if (!tag_valid)
#endif
sc->sc_dma_tag = bus_get_dma_tag(dev);
+
+#ifdef PCI_EHP
+ pci_hotplug_init(dev);
+#endif
+
return (0);
}
static int
pci_attach(device_t dev)
{
- int busno, domain, error;
+ int error;
error = pci_attach_common(dev);
if (error)
@@ -3701,9 +3734,7 @@
* the unit number to decide which bus we are probing. We ask
* the parent pcib what our domain and bus numbers are.
*/
- domain = pcib_get_domain(dev);
- busno = pcib_get_bus(dev);
- pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo));
+ pci_add_children(dev);
return (bus_generic_attach(dev));
}
@@ -3806,20 +3837,14 @@
case PCIC_BRIDGE:
case PCIC_BASEPERIPH:
BUS_RESUME_CHILD(dev, child);
+ devlist[i] = NULL;
break;
}
}
for (i = 0; i < numdevs; i++) {
child = devlist[i];
- switch (pci_get_class(child)) {
- case PCIC_DISPLAY:
- case PCIC_MEMORY:
- case PCIC_BRIDGE:
- case PCIC_BASEPERIPH:
- break;
- default:
+ if (child != NULL)
BUS_RESUME_CHILD(dev, child);
- }
}
free(devlist, M_TEMP);
return (0);
@@ -5374,3 +5399,25 @@
return (PCIB_GET_RID(device_get_parent(dev), child));
}
+
+static int
+pci_child_present(device_t pcib, uint8_t b, uint8_t s, uint8_t f)
+{
+
+ if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != 0xfffffffful)
+ return -1; /* present */
+
+ return 0;
+}
+
+static int
+pci_bus_child_present(device_t dev, device_t child)
+{
+ uint8_t b, s, f;
+
+ b = pci_get_bus(child);
+ s = pci_get_slot(child);
+ f = pci_get_function(child);
+
+ return pci_child_present(device_get_parent(dev), b, s, f);
+}
Index: sys/dev/pci/pci_if.m
===================================================================
--- sys/dev/pci/pci_if.m
+++ sys/dev/pci/pci_if.m
@@ -202,6 +202,18 @@
device_t child;
};
+
+#
+# Add a new child at slot/function. It is expected that the device is known
+# to be present, but a NULL device_t handle may be returned if there was an
+# issue adding the device.
+#
+METHOD device_t add_child {
+ device_t dev;
+ uint8_t slot;
+ uint8_t func;
+};
+
METHOD int iov_attach {
device_t dev;
device_t child;
Index: sys/dev/pci/pci_private.h
===================================================================
--- sys/dev/pci/pci_private.h
+++ sys/dev/pci/pci_private.h
@@ -48,9 +48,10 @@
extern int pci_do_power_resume;
extern int pci_do_power_suspend;
-void pci_add_children(device_t dev, int domain, int busno,
- size_t dinfo_size);
+void pci_add_children(device_t dev);
void pci_add_child(device_t bus, struct pci_devinfo *dinfo);
+device_t pci_add_child_size(device_t dev, uint8_t s, uint8_t f,
+ size_t dinfo_size);
device_t pci_add_iov_child(device_t bus, device_t pf, size_t dinfo_size,
uint16_t rid, uint16_t vid, uint16_t did);
void pci_add_resources(device_t bus, device_t dev, int force,
@@ -114,8 +115,7 @@
void pci_delete_resource(device_t dev, device_t child,
int type, int rid);
struct resource_list *pci_get_resource_list (device_t dev, device_t child);
-struct pci_devinfo *pci_read_device(device_t pcib, int d, int b, int s, int f,
- size_t size);
+struct pci_devinfo *pci_read_device(device_t pcib, uint32_t d, uint8_t b, uint8_t s, uint8_t f, size_t size);
void pci_print_verbose(struct pci_devinfo *dinfo);
int pci_freecfg(struct pci_devinfo *dinfo);
void pci_child_detached(device_t dev, device_t child);
@@ -152,6 +152,8 @@
int type, int *rid, u_long start, u_long end, u_long count,
u_long num, u_int flags);
+void pci_hotplug_init(device_t dev);
+
int pci_iov_attach_method(device_t bus, device_t dev,
struct nvlist *pf_schema, struct nvlist *vf_schema);
int pci_iov_detach_method(device_t bus, device_t dev);
Index: sys/dev/pci/pcie_hp.c
===================================================================
--- /dev/null
+++ sys/dev/pci/pcie_hp.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2012, Gavin Atkinson <gavin@FreeBSD.org>
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship from the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+#include "opt_kdtrace.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#include <sys/endian.h>
+#include <sys/sdt.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+#include <machine/intr_machdep.h>
+#endif
+
+#include <sys/pciio.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h>
+
+#include "pcib_if.h"
+#include "pci_if.h"
+
+SDT_PROVIDER_DEFINE(pci);
+
+SDT_PROBE_DEFINE2(pci, pciehp, intr, entry, "uint32_t", "uint32_t");
+SDT_PROBE_DEFINE4(pci, pciehp, task, entry, "uint32_t", "uint32_t",
+ "uint32_t", "uint32_t");
+SDT_PROBE_DEFINE(pci, pciehp, task, add_children);
+SDT_PROBE_DEFINE(pci, pciehp, task, remove_children);
+SDT_PROBE_DEFINE(pci, pciehp, task, ignored);
+SDT_PROBE_DEFINE1(pci, pciehp, task, other, "uint32_t");
+
+static struct resource_spec hotplug_res_spec_msi[] = {
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+
+static void
+pci_link_status_print(device_t pcib)
+{
+ struct pci_devinfo *dinfo;
+ int link_sta, pos;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+ link_sta = pci_read_config(pcib, pos + PCIER_LINK_STA, 2);
+ device_printf(pcib, "... LINK_STA=0x%b, width %dx\n",
+ link_sta,
+ "\020"
+#if 0
+ "\001<b0>"
+ "\002<b1>"
+ "\003<b2>"
+ "\004<b3>"
+ "\005<b4>"
+ "\006<b5>"
+ "\007<b6>"
+ "\010<b7>"
+ "\011<b8>"
+ "\012<b9>"
+ "\013Undef"
+#endif
+ "\014LinkTrain"
+ "\015SlotClkConfig"
+ "\016DLLLinkActive"
+ "\017LinkBWManStat"
+ "\020LinkAutonBwStat",
+ (link_sta & 0x03f0) >> 4);
+}
+
+static int power_values[] = { 250, 275, 300 };
+
+static void
+pci_slot_cap_power(uint32_t reg, char buf[6])
+{
+ int val, mag;
+ int whole, fract, fractcnt, fractmul;
+ int avail;
+
+ val = (reg >> 7) & 0xff;
+ mag = (reg >> 15) & 0x3;
+ fract = 0;
+ fractcnt = 0;
+ if (val < 0xf0) {
+ fractmul = 1;
+ whole = val;
+ while (mag--) {
+ fract += (whole % 10) * fractmul;
+ whole /= 10;
+ fractcnt++;
+ fractmul *= 10;
+ }
+ } else {
+ if (val < 0xf3)
+ whole = power_values[val - 0xf0];
+ else
+ whole = 301;
+ }
+ avail = 6;
+ snprintf(buf, avail, "%d", whole);
+ if (fractcnt) {
+ avail -= strlen(buf);
+ buf += strlen(buf);
+ snprintf(buf, avail, ".%0*d", fractcnt, fract);
+ }
+}
+
+static void
+pci_slot_cap_print(device_t pcib)
+{
+ char buf[6];
+ struct pci_devinfo *dinfo;
+ int pos;
+ uint32_t reg;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+ reg = pci_read_config(pcib, pos+PCIER_SLOT_CAP, 4);
+ pci_slot_cap_power(reg, buf);
+ device_printf(pcib, "... SLOT_CAP=0x%b, #%u, %sW\n", reg,
+ "\020"
+ "\001AttnButt"
+ "\002PowerCtrl"
+ "\003MRLSens"
+ "\004AttnInd"
+ "\005PwrInd"
+ "\006HotPlugSurp"
+ "\007HotPlugCap"
+#if 0
+ "\010<b7>"
+ "\011<b8>"
+ "\012<b9>"
+ "\013<b10>"
+ "\014<b11>"
+ "\015<b12>"
+ "\016<b13>"
+ "\017<b14>"
+ "\020<b15>"
+ "\021<b16>"
+#endif
+ "\022ElecMechInt"
+ "\023NoCCS"
+#if 0
+ "\024<b19>"
+ "\025<b20>"
+ "\026<b21>"
+ "\027<b22>"
+#endif
+ , PCIEM_SLOT_CAP_GETPSN(reg), buf);
+}
+
+static void
+pci_slot_control_print(device_t pcib)
+{
+ struct pci_devinfo *dinfo;
+ int pos;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+ device_printf(pcib, "... SLOT_CTL=0x%b\n",
+ pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2),
+ "\020"
+ "\001AttnButtPressEn"
+ "\002PowerFaultDetEn"
+ "\003MRLSensChgEn"
+ "\004PresDetChgEn"
+ "\005CmdCompIntEn"
+ "\006HotPlugIntEn"
+ "\007AttnIndCtl1"
+ "\010AttnIndCtl2"
+ "\012PwrIndCtl2"
+ "\013PwrCtrlrCtl"
+ "\014ElecMechIntCtl"
+ "\015DLLStatChEn"
+#if 0
+ "\016<b13>"
+ "\017<b14>"
+ "\020<b15>"
+#endif
+ );
+}
+
+static void
+pci_slot_status_print(device_t pcib)
+{
+ struct pci_devinfo *dinfo;
+ int pos;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+ device_printf(pcib, "... SLOT_STA=0x%b\n",
+ pci_read_config(pcib, pos + PCIER_SLOT_STA, 2),
+ "\020"
+ "\001AttnButtPress"
+ "\002PowerFaultDet"
+ "\003MRLSensChg"
+ "\004PresDetChg"
+ "\005CmdComplete"
+ "\006MRLSensState"
+ "\007PresDetState"
+ "\010ElecMechIntState"
+ "\011DLLStateChg"
+#if 0
+ "\012<b9>"
+ "\013<b10>"
+ "\014<b11>"
+ "\015<b12>"
+ "\016<b13>"
+ "\017<b14>"
+ "\020<b15>"
+#endif
+ );
+}
+
+void pci_slot_reg_print(device_t pcib);
+void
+pci_slot_reg_print(device_t pcib)
+{
+
+ pci_link_status_print(pcib);
+ pci_slot_cap_print(pcib);
+ pci_slot_status_print(pcib);
+ pci_slot_control_print(pcib);
+}
+
+static void
+rescan_bus(void *arg)
+{
+ device_t dev;
+
+ dev = arg;
+
+ SDT_PROBE(pci, pciehp, task, add_children, 0, 0, 0, 0, 0);
+ pci_add_children(dev);
+ (void)bus_generic_attach(dev);
+
+}
+
+static void
+pci_hotplug_intr_task(void *arg, int npending)
+{
+ device_t dev;
+ device_t pcib;
+ device_t *devlistp;
+ struct pci_devinfo *dinfo;
+ int devcnt, i, pos;
+ uint32_t linksta, slotsta, staclr;
+ uint16_t ctrl;
+
+ dev = arg;
+ pcib = device_get_parent(dev);
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+
+ mtx_lock(&Giant);
+
+ linksta = pci_read_config(pcib, pos + PCIER_LINK_STA, 2);
+ slotsta = pci_read_config(pcib, pos + PCIER_SLOT_STA, 2);
+ staclr = 0;
+
+ SDT_PROBE(pci, pciehp, task, entry,
+ slotsta,
+ linksta,
+ pci_read_config(pcib, pos + PCIER_SLOT_CAP, 2),
+ pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2),
+ 0);
+#if 0
+ pci_slot_reg_print(pcib);
+#endif
+/* XXXGA: HACK AHEAD */
+ if (slotsta & PCIEM_SLOT_STA_CC) {
+ /* XXX - handle command completed events to advance state machine */
+ }
+
+ if (slotsta & PCIEM_SLOT_STA_PDC && /* presence change */
+ dinfo->cfg.hp.hp_slotcap & PCIEM_SLOT_CAP_PCP && /* power ctrlr */
+ slotsta & PCIEM_SLOT_STA_PDS) { /* present */
+ ctrl = pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2);
+ ctrl &= ~PCIEM_SLOT_CTL_PCC;
+ pci_write_config(pcib, pos + PCIER_SLOT_CTL, ctrl, 2);
+ staclr |= PCIEM_SLOT_STA_PDC;
+ /* XXX - start timeout */
+ }
+
+ if (slotsta & PCIEM_SLOT_STA_PDC && /* presence change */
+ dinfo->cfg.hp.hp_slotcap & PCIEM_SLOT_CAP_PCP && /* power ctrlr */
+ !(slotsta & PCIEM_SLOT_STA_PDS)) { /* not present */
+ ctrl = pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2);
+ ctrl |= PCIEM_SLOT_CTL_PCC;
+ pci_write_config(pcib, pos + PCIER_SLOT_CTL, ctrl, 2);
+ staclr |= PCIEM_SLOT_STA_PDC;
+ }
+
+ if (slotsta & PCIEM_SLOT_STA_DLLSC) {
+ if ((linksta & PCIEM_LINK_STA_DL_ACTIVE) &&
+ dinfo->cfg.hp.hp_cnt == 0) {
+ dinfo->cfg.hp.hp_cnt = 1;
+ /*
+ * Per 6.7.3.3, delay for 100ms after DLL Active
+ * before talking to device.
+ */
+ callout_reset(&dinfo->cfg.hp.hp_co, hz / 10,
+ rescan_bus, dev);
+ } else if (((linksta & PCIEM_LINK_STA_DL_ACTIVE) == 0) &&
+ dinfo->cfg.hp.hp_cnt == 1) {
+
+ /*
+ * XXX - do we do the code here or when it is no
+ * longer present?
+ */
+ SDT_PROBE(pci, pciehp, task, remove_children, 0, 0, 0, 0, 0);
+ device_get_children(dev, &devlistp, &devcnt);
+ for (i = 0; i < devcnt; i++)
+ pci_delete_child(dev, devlistp[i]);
+ free(devlistp, M_TEMP);
+ dinfo->cfg.hp.hp_cnt = 0;
+ } else
+ SDT_PROBE(pci, pciehp, task, ignored, 0, 0, 0, 0, 0);
+
+ staclr |= PCIEM_SLOT_STA_DLLSC;
+ }
+
+ /* we only care about bits we can clear after here */
+ slotsta &= PCIEM_SLOT_STA_EMASK;
+
+ /* log any status changes we didn't handle */
+ if (slotsta & ~staclr)
+ SDT_PROBE(pci, pciehp, task, other,
+ slotsta & ~staclr, 0, 0, 0, 0);
+
+ /* always clear the sta reg as if we don't, we get an interrupt storm */
+ pci_write_config(pcib, pos + PCIER_SLOT_STA, slotsta, 2);
+
+ mtx_unlock(&Giant);
+}
+
+static int
+pci_hotplug_intr(void *arg)
+{
+ device_t dev = arg;
+ device_t pcib = device_get_parent(dev);
+ struct pci_devinfo *dinfo;
+ int pos;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+
+ SDT_PROBE(pci, pciehp, intr, entry,
+ pci_read_config(pcib, pos + PCIER_SLOT_STA, 2),
+ pci_read_config(pcib, pos + PCIER_LINK_STA, 2),
+ 0, 0, 0);
+#if 0
+ device_printf(dev, "Received interrupt!\n");
+ pci_slot_status_print(pcib);
+#endif
+ taskqueue_enqueue_fast(taskqueue_fast, &dinfo->cfg.hp.hp_inttask);
+
+ return (FILTER_HANDLED);
+}
+
+/*
+ * XXX - Make sure the minimum allocations are done.
+ *
+ * Minimum allocations for ExpressCard:
+ * 8 busses
+ * 0 Prefetchable
+ * 32Meg non-prefetchable
+ * 4k I/O
+ */
+static void
+pci_hotplug_setup(device_t dev)
+{
+ device_t pcib = device_get_parent(dev);
+ struct pci_devinfo *dinfo;
+ int cap, error, flags, msic, pos;
+ uint16_t slotctl;
+
+ dinfo = device_get_ivars(pcib);
+
+ pos = dinfo->cfg.pcie.pcie_location;
+ flags = pci_read_config(pcib, pos + PCIER_FLAGS, 2);
+ cap = pci_read_config(pcib, pos + PCIER_SLOT_CAP, 4);
+ dinfo->cfg.hp.hp_slotcap = cap;
+
+ if (bootverbose)
+ pci_slot_status_print(pcib);
+
+ dinfo->cfg.hp.hp_cnt = 0;
+ callout_init(&dinfo->cfg.hp.hp_co, 0);
+
+ device_printf(dev, "Hot plug slot number %u\n",
+ PCIEM_SLOT_CAP_GETPSN(cap));
+
+ if (!(cap & PCIEM_SLOT_CAP_NCCS))
+ device_printf(dev, "WARNING! Command Completion Status not supported!");
+
+#if 0
+ /*
+ * IRQ is ignored as PCIe requires MSI. It is possible that we could
+ * have PCIe devices on a PCI bus on a motherboard that doesn't
+ * support MSI, but I hope that we'll do the proper work in the bus
+ * code to support it.
+ */
+ int irq;
+ irq = (flags & PCIEM_FLAGS_IRQ) >> 9;
+ device_printf(dev, "IRQ = %d\n", irq);
+ device_printf(dev, "MSI count self %d parent %d\n",
+ pci_msi_count(dev), pci_msi_count(pcib));
+ device_printf(dev, "MSI-X count self %d parent %d\n",
+ pci_msix_count(dev), pci_msix_count(pcib));
+#endif
+ msic = pci_msi_count(pcib);
+ if (msic) {
+ /* I've seen a device w/ 8 MSI, but the first one works. */
+ msic = 1;
+ if (pci_alloc_msi(pcib, &msic) == 0) {
+ if (msic == 1) {
+ device_printf(dev,
+ "Using %d MSI messages\n",
+ msic);
+ dinfo->cfg.pcie.pcie_irq_spec =
+ hotplug_res_spec_msi;
+ } else {
+ device_printf(dev,
+ "Error: %d MSI messages, ABORTING.\n",
+ msic);
+ pci_release_msi(dev);
+ return;
+ }
+ }
+ }
+ error = bus_alloc_resources(pcib,
+ dinfo->cfg.pcie.pcie_irq_spec,
+ dinfo->cfg.pcie.pcie_res_irq);
+ if (error) {
+ device_printf(dev,
+ "couldn't allocate IRQ resources, %d, ABORTING.\n",
+ error);
+ return;
+ } else {
+ error = bus_setup_intr(pcib,
+ dinfo->cfg.pcie.pcie_res_irq[0],
+ INTR_TYPE_AV | INTR_MPSAFE,
+ pci_hotplug_intr, NULL, dev,
+ &dinfo->cfg.pcie.pcie_intrhand[0]);
+ if (error) {
+ device_printf(dev, "couldn't set up IRQ resources, %d\n",
+ error);
+ }
+ }
+
+ TASK_INIT(&dinfo->cfg.hp.hp_inttask, 0,
+ pci_hotplug_intr_task, dev);
+
+ /* Select and enable events to interrupt upon */
+ slotctl = pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2);
+ slotctl |= PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_HPIE;
+ if (cap & PCIEM_SLOT_CAP_MRLSP)
+ slotctl |= PCIEM_SLOT_CTL_MRLSCE;
+ if (pci_read_config(pcib, pos + PCIER_LINK_CAP, 4) &
+ PCIEM_LINK_CAP_DL_ACTIVE)
+ slotctl |= PCIEM_SLOT_CTL_DLLSCE;
+ pci_write_config(pcib, pos + PCIER_SLOT_CTL, slotctl, 2);
+ if (bootverbose) {
+ device_printf(dev, "Enabled interrupts\n");
+ pci_slot_control_print(pcib);
+ pci_slot_status_print(pcib);
+ }
+
+ /* XXX - Do we check for presence? */
+ if (pci_read_config(pcib, pos + PCIER_LINK_STA,
+ 2) & PCIEM_LINK_STA_DL_ACTIVE) {
+ dinfo->cfg.hp.hp_cnt = 1;
+ /* XXX - should we wait 100ms? */
+ }
+}
+
+void
+pci_hotplug_init(device_t dev)
+{
+ device_t pcib = device_get_parent(dev);
+ struct pci_devinfo *dinfo;
+ int cap, flags, pos;
+
+ dinfo = device_get_ivars(pcib);
+ pos = dinfo->cfg.pcie.pcie_location;
+ if (pos != 0) {
+ flags = pci_read_config(pcib, pos + PCIER_FLAGS, 2);
+ cap = pci_read_config(pcib, pos + PCIER_SLOT_CAP, 4);
+ if (bootverbose)
+ pci_slot_cap_print(pcib);
+ if ((flags & PCIEM_FLAGS_SLOT &&
+ cap & PCIEM_SLOT_CAP_HPC)) {
+ pci_hotplug_setup(dev);
+ }
+ }
+}
Index: sys/dev/pci/pcireg.h
===================================================================
--- sys/dev/pci/pcireg.h
+++ sys/dev/pci/pcireg.h
@@ -768,6 +768,7 @@
#define PCIEM_SLOT_CAP_EIP 0x00020000
#define PCIEM_SLOT_CAP_NCCS 0x00040000
#define PCIEM_SLOT_CAP_PSN 0xfff80000
+#define PCIEM_SLOT_CAP_GETPSN(x) (((x) & PCIEM_SLOT_CAP_PSN) >> 19)
#define PCIER_SLOT_CTL 0x18
#define PCIEM_SLOT_CTL_ABPE 0x0001
#define PCIEM_SLOT_CTL_PFDE 0x0002
@@ -790,6 +791,7 @@
#define PCIEM_SLOT_STA_PDS 0x0040
#define PCIEM_SLOT_STA_EIS 0x0080
#define PCIEM_SLOT_STA_DLLSC 0x0100
+#define PCIEM_SLOT_STA_EMASK 0x011f
#define PCIER_ROOT_CTL 0x1c
#define PCIEM_ROOT_CTL_SERR_CORR 0x0001
#define PCIEM_ROOT_CTL_SERR_NONFATAL 0x0002
Index: sys/dev/pci/pcivar.h
===================================================================
--- sys/dev/pci/pcivar.h
+++ sys/dev/pci/pcivar.h
@@ -30,7 +30,11 @@
#ifndef _PCIVAR_H_
#define _PCIVAR_H_
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/queue.h>
+#include <sys/taskqueue.h>
/* some PCI bus constants */
#define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */
@@ -133,6 +137,8 @@
uint64_t ht_msiaddr; /* MSI mapping base address */
};
+#define PCIE_MSI_MESSAGES 2
+
/* Interesting values for PCI-express */
struct pcicfg_pcie {
uint8_t pcie_location; /* Offset of PCI-e capability registers. */
@@ -145,6 +151,9 @@
uint16_t pcie_device_ctl2; /* Second device control register. */
uint16_t pcie_link_ctl2; /* Second link control register. */
uint16_t pcie_slot_ctl2; /* Second slot control register. */
+ struct resource_spec *pcie_irq_spec;
+ struct resource *pcie_res_irq[PCIE_MSI_MESSAGES];
+ void *pcie_intrhand[PCIE_MSI_MESSAGES];
};
struct pcicfg_pcix {
@@ -156,6 +165,14 @@
int index;
};
+/* Interesting values for PCIe Hotplug */
+struct pcicfg_hp {
+ struct task hp_inttask;
+ struct callout hp_co;
+ int hp_cnt; /* Giant locked */
+ uint32_t hp_slotcap; /* cache this */
+};
+
#define PCICFG_VF 0x0001 /* Device is an SR-IOV Virtual Function */
/* config header information common to all header types */
@@ -207,6 +224,7 @@
struct pcicfg_pcix pcix; /* PCI-X */
struct pcicfg_iov *iov; /* SR-IOV */
struct pcicfg_vf vf; /* SR-IOV Virtual Function */
+ struct pcicfg_hp hp; /* Hotplug */
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 12, 8:49 PM (12 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17125903
Default Alt Text
D3932.diff (27 KB)

Event Timeline