Page MenuHomeFreeBSD

D19646.id55560.diff
No OneTemporary

D19646.id55560.diff

Index: lib/libdevctl/devctl.h
===================================================================
--- lib/libdevctl/devctl.h
+++ lib/libdevctl/devctl.h
@@ -30,6 +30,7 @@
#include <stdbool.h>
+__BEGIN_DECLS
int devctl_attach(const char *device);
int devctl_detach(const char *device, bool force);
int devctl_enable(const char *device);
@@ -42,5 +43,7 @@
int devctl_delete(const char *device, bool force);
int devctl_freeze(void);
int devctl_thaw(void);
+int devctl_reset(const char *device, bool detach);
+__END_DECLS
#endif /* !__DEVCTL_H__ */
Index: lib/libdevctl/devctl.c
===================================================================
--- lib/libdevctl/devctl.c
+++ lib/libdevctl/devctl.c
@@ -158,3 +158,11 @@
return (devctl_simple_request(DEV_THAW, "", 0));
}
+
+int
+devctl_reset(const char *device, bool detach)
+{
+
+ return (devctl_simple_request(DEV_RESET, device, detach ?
+ DEVF_RESET_DETACH : 0));
+}
Index: sys/amd64/vmm/io/ppt.c
===================================================================
--- sys/amd64/vmm/io/ppt.c
+++ sys/amd64/vmm/io/ppt.c
@@ -356,25 +356,12 @@
static void
ppt_pci_reset(device_t dev)
{
- int ps;
if (pcie_flr(dev,
- max(pcie_get_max_completion_timeout(dev) / 1000, 10),
- true))
+ max(pcie_get_max_completion_timeout(dev) / 1000, 10), true))
return;
- /*
- * If FLR fails, attempt a power-management reset by cycling
- * the device in/out of D3 state.
- * PCI spec says we can only go into D3 state from D0 state.
- * Transition from D[12] into D0 before going to D3 state.
- */
- ps = pci_get_powerstate(dev);
- if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3)
- pci_set_powerstate(dev, PCI_POWERSTATE_D0);
- if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3)
- pci_set_powerstate(dev, PCI_POWERSTATE_D3);
- pci_set_powerstate(dev, ps);
+ pci_power_reset(dev);
}
int
Index: sys/dev/pci/pci.c
===================================================================
--- sys/dev/pci/pci.c
+++ sys/dev/pci/pci.c
@@ -125,6 +125,9 @@
u_int irq);
static void pci_hint_device_unit(device_t acdev, device_t child,
const char *name, int *unitp);
+static int pci_reset_post(device_t dev, device_t child);
+static int pci_reset_prepare(device_t dev, device_t child);
+static int pci_reset(device_t dev, device_t child, int flags);
static int pci_get_id_method(device_t dev, device_t child,
enum pci_id_type type, uintptr_t *rid);
@@ -149,6 +152,9 @@
DEVMETHOD(bus_driver_added, pci_driver_added),
DEVMETHOD(bus_setup_intr, pci_setup_intr),
DEVMETHOD(bus_teardown_intr, pci_teardown_intr),
+ DEVMETHOD(bus_reset_prepare, pci_reset_prepare),
+ DEVMETHOD(bus_reset_post, pci_reset_post),
+ DEVMETHOD(bus_reset, pci_reset),
DEVMETHOD(bus_get_dma_tag, pci_get_dma_tag),
DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
@@ -6365,6 +6371,89 @@
return (true);
}
+int
+pci_power_reset(device_t dev)
+{
+ int ps;
+
+ ps = pci_get_powerstate(dev);
+ if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3)
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+ pci_set_powerstate(dev, PCI_POWERSTATE_D3);
+ pci_set_powerstate(dev, ps);
+ return (0);
+}
+
+/*
+ * Try link drop and retrain of the downstream port of upstream
+ * switch, for PCIe. According to the PCIe 3.0 spec 6.6.1, this must
+ * cause Conventional Hot reset of the device in the slot.
+ * Alternative, for PCIe, could be the secondary bus reset initiatied
+ * on the upstream switch PCIR_BRIDGECTL_1, bit 6.
+ */
+int
+pcie_link_reset(device_t port, int pcie_location)
+{
+ uint16_t v;
+
+ v = pci_read_config(port, pcie_location + PCIER_LINK_CTL, 2);
+ v |= PCIEM_LINK_CTL_LINK_DIS;
+ pci_write_config(port, pcie_location + PCIER_LINK_CTL, v, 2);
+ pause_sbt("pcier1", mstosbt(20), 0, 0);
+ v &= ~PCIEM_LINK_CTL_LINK_DIS;
+ v |= PCIEM_LINK_CTL_RETRAIN_LINK;
+ pci_write_config(port, pcie_location + PCIER_LINK_CTL, v, 2);
+ pause_sbt("pcier2", mstosbt(100), 0, 0); /* 100 ms */
+ v = pci_read_config(port, pcie_location + PCIER_LINK_STA, 2);
+ return ((v & PCIEM_LINK_STA_TRAINING) != 0 ? ETIMEDOUT : 0);
+}
+
+static int
+pci_reset_post(device_t dev, device_t child)
+{
+
+ if (dev == device_get_parent(child))
+ pci_restore_state(child);
+ return (0);
+}
+
+static int
+pci_reset_prepare(device_t dev, device_t child)
+{
+
+ if (dev == device_get_parent(child))
+ pci_save_state(child);
+ return (0);
+}
+
+static int
+pci_reset(device_t dev, device_t child, int flags)
+{
+ int error;
+
+ if (dev == NULL || device_get_parent(child) != dev)
+ return (0);
+ if ((flags & DEVF_RESET_DETACH) != 0) {
+ error = device_get_state(child) == DS_ATTACHED ?
+ device_detach(child) : 0;
+ } else {
+ error = BUS_SUSPEND_CHILD(dev, child);
+ }
+ if (error == 0) {
+ if (!pcie_flr(child, 1000, false)) {
+ error = BUS_RESET_PREPARE(dev, child);
+ if (error == 0)
+ pci_power_reset(child);
+ BUS_RESET_POST(dev, child);
+ }
+ if ((flags & DEVF_RESET_DETACH) != 0)
+ device_probe_and_attach(child);
+ else
+ BUS_RESUME_CHILD(dev, child);
+ }
+ return (error);
+}
+
const struct pci_device_table *
pci_match_device(device_t child, const struct pci_device_table *id, size_t nelt)
{
Index: sys/dev/pci/pci_pci.c
===================================================================
--- sys/dev/pci/pci_pci.c
+++ sys/dev/pci/pci_pci.c
@@ -44,6 +44,7 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/pciio.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
@@ -80,6 +81,7 @@
#endif
static int pcib_request_feature_default(device_t pcib, device_t dev,
enum pci_feature feature);
+static int pcib_reset(device_t dev, device_t child, int flags);
static device_method_t pcib_methods[] = {
/* Device interface */
@@ -106,6 +108,7 @@
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_reset, pcib_reset),
/* pcib interface */
DEVMETHOD(pcib_maxslots, pcib_ari_maxslots),
@@ -2909,3 +2912,31 @@
bus = device_get_parent(pcib);
return (PCIB_REQUEST_FEATURE(device_get_parent(bus), dev, feature));
}
+
+static int
+pcib_reset(device_t dev, device_t child, int flags)
+{
+ struct pci_devinfo *pdinfo;
+ int error;
+
+ error = 0;
+ if (dev == NULL || device_get_parent(child) != dev)
+ goto out;
+ error = ENXIO;
+ if (device_get_devclass(child) != devclass_find("pci"))
+ goto out;
+ pdinfo = device_get_ivars(dev);
+ if (pdinfo->cfg.pcie.pcie_location != 0 &&
+ (pdinfo->cfg.pcie.pcie_type != PCIEM_TYPE_DOWNSTREAM_PORT ||
+ pdinfo->cfg.pcie.pcie_type == PCIEM_TYPE_ROOT_PORT)) {
+ error = bus_helper_reset_prepare(child, flags);
+ if (error == 0) {
+ error = pcie_link_reset(dev,
+ pdinfo->cfg.pcie.pcie_location);
+ /* XXXKIB call _post even if error != 0 ? */
+ bus_helper_reset_post(child, flags);
+ }
+ }
+out:
+ return (error);
+}
Index: sys/dev/pci/pcivar.h
===================================================================
--- sys/dev/pci/pcivar.h
+++ sys/dev/pci/pcivar.h
@@ -681,6 +681,7 @@
void pci_restore_state(device_t dev);
void pci_save_state(device_t dev);
int pci_set_max_read_req(device_t dev, int size);
+int pci_power_reset(device_t dev);
uint32_t pcie_read_config(device_t dev, int reg, int width);
void pcie_write_config(device_t dev, int reg, uint32_t value, int width);
uint32_t pcie_adjust_config(device_t dev, int reg, uint32_t mask,
@@ -688,6 +689,7 @@
bool pcie_flr(device_t dev, u_int max_delay, bool force);
int pcie_get_max_completion_timeout(device_t dev);
bool pcie_wait_for_pending_transactions(device_t dev, u_int max_delay);
+int pcie_link_reset(device_t port, int pcie_location);
void pci_print_faulted_dev(void);
Index: sys/dev/smartpqi/smartpqi_cam.c
===================================================================
--- sys/dev/smartpqi/smartpqi_cam.c
+++ sys/dev/smartpqi/smartpqi_cam.c
@@ -739,7 +739,7 @@
return error;
}
/* Check device reset */
- if (DEV_RESET(dvp)) {
+ if (dvp->reset_in_progress) {
ccb->ccb_h.status = CAM_SCSI_BUSY | CAM_REQ_INPROG | CAM_BUSY;
DBG_WARN("Device %d reset returned busy\n", ccb->ccb_h.target_id);
return error;
Index: sys/dev/smartpqi/smartpqi_defines.h
===================================================================
--- sys/dev/smartpqi/smartpqi_defines.h
+++ sys/dev/smartpqi/smartpqi_defines.h
@@ -386,8 +386,6 @@
#define IS_AIO_PATH(dev) (dev->aio_enabled)
#define IS_RAID_PATH(dev) (!dev->aio_enabled)
-#define DEV_RESET(dvp) (dvp->reset_in_progress)
-
/* SOP data direction flags */
#define SOP_DATA_DIR_NONE 0x00
#define SOP_DATA_DIR_FROM_DEVICE 0x01
Index: sys/kern/bus_if.m
===================================================================
--- sys/kern/bus_if.m
+++ sys/kern/bus_if.m
@@ -66,6 +66,16 @@
panic("bus_add_child is not implemented");
}
+
+ static int null_reset_post(device_t bus, device_t dev)
+ {
+ return (0);
+ }
+
+ static int null_reset_prepare(device_t bus, device_t dev)
+ {
+ return (0);
+ }
};
/**
@@ -848,3 +858,19 @@
size_t _setsize;
cpuset_t *_cpuset;
} DEFAULT bus_generic_get_cpus;
+
+METHOD int reset_prepare {
+ device_t _dev;
+ device_t _child;
+} DEFAULT null_reset_prepare;
+
+METHOD int reset_post {
+ device_t _dev;
+ device_t _child;
+} DEFAULT null_reset_post;
+
+METHOD int reset {
+ device_t _dev;
+ device_t _child;
+ int _flags;
+} DEFAULT null_reset;
Index: sys/kern/subr_bus.c
===================================================================
--- sys/kern/subr_bus.c
+++ sys/kern/subr_bus.c
@@ -3864,6 +3864,79 @@
return (0);
}
+int
+bus_helper_reset_post(device_t dev, int flags)
+{
+ device_t child;
+ int error, error1;
+
+ error = 0;
+ TAILQ_FOREACH(child, &dev->children,link) {
+ BUS_RESET_POST(dev, child);
+ if ((flags & DEVF_RESET_DETACH) != 0) {
+ if (device_get_state(child) != DS_ATTACHED)
+ error1 = device_probe_and_attach(child);
+ } else {
+ error1 = BUS_RESUME_CHILD(dev, child);
+ }
+ if (error == 0 && error1 != 0)
+ error = error1;
+ }
+ return (error);
+}
+
+static void
+bus_helper_reset_prepare_rollback(device_t dev, device_t child, int flags)
+{
+
+ child = TAILQ_NEXT(child, link);
+ if (child == NULL)
+ return;
+ TAILQ_FOREACH_FROM(child, &dev->children,link) {
+ BUS_RESET_POST(dev, child);
+ if ((flags & DEVF_RESET_DETACH) != 0) {
+ if (device_get_state(child) != DS_ATTACHED)
+ device_probe_and_attach(child);
+ } else {
+ BUS_RESUME_CHILD(dev, child);
+ }
+ }
+}
+
+int
+bus_helper_reset_prepare(device_t dev, int flags)
+{
+ device_t child;
+ int error;
+
+ if (dev->state != DS_ATTACHED)
+ return (EBUSY);
+
+ TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) {
+ if ((flags & DEVF_RESET_DETACH) != 0) {
+ error = device_get_state(child) == DS_ATTACHED ?
+ device_detach(child) : 0;
+ } else {
+ error = BUS_SUSPEND_CHILD(dev, child);
+ }
+ if (error == 0) {
+ error = BUS_RESET_PREPARE(dev, child);
+ if (error != 0) {
+ if ((flags & DEVF_RESET_DETACH) != 0)
+ device_probe_and_attach(child);
+ else
+ BUS_RESUME_CHILD(dev, child);
+ }
+ }
+ if (error != 0) {
+ bus_helper_reset_prepare_rollback(dev, child, flags);
+ return (error);
+ }
+ }
+ return (0);
+}
+
+
/**
* @brief Helper function for implementing BUS_PRINT_CHILD().
*
@@ -5556,6 +5629,7 @@
case DEV_CLEAR_DRIVER:
case DEV_RESCAN:
case DEV_DELETE:
+ case DEV_RESET:
error = priv_check(td, PRIV_DRIVER);
if (error == 0)
error = find_device(req, &dev);
@@ -5781,6 +5855,14 @@
device_frozen = false;
}
break;
+ case DEV_RESET:
+ if ((req->dr_flags & ~(DEVF_RESET_DETACH)) != 0) {
+ error = EINVAL;
+ break;
+ }
+ error = BUS_RESET(device_get_parent(dev), dev,
+ req->dr_flags);
+ break;
}
mtx_unlock(&Giant);
return (error);
Index: sys/sys/bus.h
===================================================================
--- sys/sys/bus.h
+++ sys/sys/bus.h
@@ -130,6 +130,7 @@
#define DEV_DELETE _IOW('D', 10, struct devreq)
#define DEV_FREEZE _IOW('D', 11, struct devreq)
#define DEV_THAW _IOW('D', 12, struct devreq)
+#define DEV_RESET _IOW('D', 13, struct devreq)
/* Flags for DEV_DETACH and DEV_DISABLE. */
#define DEVF_FORCE_DETACH 0x0000001
@@ -143,6 +144,10 @@
/* Flags for DEV_DELETE. */
#define DEVF_FORCE_DELETE 0x0000001
+/* Flags for DEV_RESET */
+#define DEVF_RESET_DETACH 0x0000001 /* Detach drivers vs suspend
+ device */
+
#ifdef _KERNEL
#include <sys/eventhandler.h>
@@ -494,6 +499,8 @@
struct resource_map *map);
int bus_generic_write_ivar(device_t dev, device_t child, int which,
uintptr_t value);
+int bus_helper_reset_post(device_t dev, int flags);
+int bus_helper_reset_prepare(device_t dev, int flags);
int bus_null_rescan(device_t dev);
/*
Index: usr.sbin/devctl/devctl.c
===================================================================
--- usr.sbin/devctl/devctl.c
+++ usr.sbin/devctl/devctl.c
@@ -82,7 +82,9 @@
" devctl rescan device\n"
" devctl delete [-f] device\n"
" devctl freeze\n"
- " devctl thaw\n");
+ " devctl thaw\n"
+ " devctl reset [-d] device\n"
+ );
exit(1);
}
@@ -384,6 +386,40 @@
}
DEVCTL_COMMAND(top, thaw, thaw);
+static void
+reset_usage(void)
+{
+
+ fprintf(stderr, "usage: devctl reset [-d] device\n");
+ exit(1);
+}
+
+static int
+reset(int ac, char **av)
+{
+ bool detach;
+ int ch;
+
+ detach = false;
+ while ((ch = getopt(ac, av, "d")) != -1)
+ switch (ch) {
+ case 'd':
+ detach = true;
+ break;
+ default:
+ reset_usage();
+ }
+ ac -= optind;
+ av += optind;
+
+ if (ac != 1)
+ reset_usage();
+ if (devctl_reset(av[0], detach) < 0)
+ err(1, "Failed to reset %s", av[0]);
+ return (0);
+}
+DEVCTL_COMMAND(top, reset, reset);
+
int
main(int ac, char *av[])
{

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 3, 11:15 AM (5 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29196928
Default Alt Text
D19646.id55560.diff (13 KB)

Event Timeline