Commit d7e02c08 authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/aer'

  - unify AER decoding for native and ACPI CPER sources (Alexandru Gagniuc)

  - add TLP header info to AER tracepoint (Thomas Tai)

  - add generic pcie_wait_for_link() interface (Oza Pawandeep)

  - handle AER ERR_FATAL by removing and re-enumerating devices, as
    Downstream Port Containment does (Oza Pawandeep)

  - factor out common code between AER and DPC recovery (Oza Pawandeep)

  - stop triggering DPC for ERR_NONFATAL errors (Oza Pawandeep)

  - share ERR_FATAL recovery path between AER and DPC (Oza Pawandeep)

* pci/aer:
  PCI/AER: Replace struct pcie_device with pci_dev
  PCI/AER: Remove unused parameters
  PCI/AER: Decode Error Source Requester ID
  PCI/AER: Remove aer_recover_work_func() forward declaration
  PCI/DPC: Use the generic pcie_do_fatal_recovery() path
  PCI/AER: Pass service type to pcie_do_fatal_recovery()
  PCI/DPC: Disable ERR_NONFATAL handling by DPC
  PCI/portdrv: Add generic pcie_port_find_device()
  PCI/portdrv: Add generic pcie_port_find_service()
  PCI/AER: Factor out error reporting to drivers/pci/pcie/err.c
  PCI/AER: Rename error recovery interfaces to generic PCI naming
  PCI/AER: Handle ERR_FATAL with removal and re-enumeration of devices
  PCI: Add generic pcie_wait_for_link() interface
  PCI/AER: Add TLP header information to tracepoint
  PCI/AER: Unify error bit printing for native and CPER reporting
parents 60cc43fc e13d17f7
...@@ -110,7 +110,7 @@ The actual steps taken by a platform to recover from a PCI error ...@@ -110,7 +110,7 @@ The actual steps taken by a platform to recover from a PCI error
event will be platform-dependent, but will follow the general event will be platform-dependent, but will follow the general
sequence described below. sequence described below.
STEP 0: Error Event STEP 0: Error Event: ERR_NONFATAL
------------------- -------------------
A PCI bus error is detected by the PCI hardware. On powerpc, the slot A PCI bus error is detected by the PCI hardware. On powerpc, the slot
is isolated, in that all I/O is blocked: all reads return 0xffffffff, is isolated, in that all I/O is blocked: all reads return 0xffffffff,
...@@ -228,13 +228,7 @@ proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations). ...@@ -228,13 +228,7 @@ proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations).
If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform
proceeds to STEP 4 (Slot Reset) proceeds to STEP 4 (Slot Reset)
STEP 3: Link Reset STEP 3: Slot Reset
------------------
The platform resets the link. This is a PCI-Express specific step
and is done whenever a fatal error has been detected that can be
"solved" by resetting the link.
STEP 4: Slot Reset
------------------ ------------------
In response to a return value of PCI_ERS_RESULT_NEED_RESET, the In response to a return value of PCI_ERS_RESULT_NEED_RESET, the
...@@ -320,7 +314,7 @@ Failure). ...@@ -320,7 +314,7 @@ Failure).
>>> However, it probably should. >>> However, it probably should.
STEP 5: Resume Operations STEP 4: Resume Operations
------------------------- -------------------------
The platform will call the resume() callback on all affected device The platform will call the resume() callback on all affected device
drivers if all drivers on the segment have returned drivers if all drivers on the segment have returned
...@@ -332,7 +326,7 @@ a result code. ...@@ -332,7 +326,7 @@ a result code.
At this point, if a new error happens, the platform will restart At this point, if a new error happens, the platform will restart
a new error recovery sequence. a new error recovery sequence.
STEP 6: Permanent Failure STEP 5: Permanent Failure
------------------------- -------------------------
A "permanent failure" has occurred, and the platform cannot recover A "permanent failure" has occurred, and the platform cannot recover
the device. The platform will call error_detected() with a the device. The platform will call error_detected() with a
...@@ -355,6 +349,27 @@ errors. See the discussion in powerpc/eeh-pci-error-recovery.txt ...@@ -355,6 +349,27 @@ errors. See the discussion in powerpc/eeh-pci-error-recovery.txt
for additional detail on real-life experience of the causes of for additional detail on real-life experience of the causes of
software errors. software errors.
STEP 0: Error Event: ERR_FATAL
-------------------
PCI bus error is detected by the PCI hardware. On powerpc, the slot is
isolated, in that all I/O is blocked: all reads return 0xffffffff, all
writes are ignored.
STEP 1: Remove devices
--------------------
Platform removes the devices depending on the error agent, it could be
this port for all subordinates or upstream component (likely downstream
port)
STEP 2: Reset link
--------------------
The platform resets the link. This is a PCI-Express specific step and is
done whenever a fatal error has been detected that can be "solved" by
resetting the link.
STEP 3: Re-enumerate the devices
--------------------
Initiates the re-enumeration.
Conclusion; General Remarks Conclusion; General Remarks
--------------------------- ---------------------------
......
...@@ -231,25 +231,11 @@ bool pciehp_check_link_active(struct controller *ctrl) ...@@ -231,25 +231,11 @@ bool pciehp_check_link_active(struct controller *ctrl)
return ret; return ret;
} }
static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
int timeout = 1000;
if (pciehp_check_link_active(ctrl) == active)
return;
while (timeout > 0) {
msleep(10);
timeout -= 10;
if (pciehp_check_link_active(ctrl) == active)
return;
}
ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
active ? "set" : "cleared");
}
static void pcie_wait_link_active(struct controller *ctrl) static void pcie_wait_link_active(struct controller *ctrl)
{ {
__pcie_wait_link_active(ctrl, true); struct pci_dev *pdev = ctrl_dev(ctrl);
pcie_wait_for_link(pdev, true);
} }
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
......
...@@ -1535,7 +1535,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -1535,7 +1535,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0; return 0;
} }
#if defined(CONFIG_PCIEAER) || defined(CONFIG_EEH) #if defined(CONFIG_PCIEPORTBUS) || defined(CONFIG_EEH)
/** /**
* pci_uevent_ers - emit a uevent during recovery path of PCI device * pci_uevent_ers - emit a uevent during recovery path of PCI device
* @pdev: PCI device undergoing error recovery * @pdev: PCI device undergoing error recovery
......
...@@ -4138,6 +4138,35 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) ...@@ -4138,6 +4138,35 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS); return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
} }
/**
* pcie_wait_for_link - Wait until link is active or inactive
* @pdev: Bridge device
* @active: waiting for active or inactive?
*
* Use this to wait till link becomes active or inactive.
*/
bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
{
int timeout = 1000;
bool ret;
u16 lnk_status;
for (;;) {
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
if (ret == active)
return true;
if (timeout <= 0)
break;
msleep(10);
timeout -= 10;
}
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
active ? "set" : "cleared");
return false;
}
void pci_reset_secondary_bus(struct pci_dev *dev) void pci_reset_secondary_bus(struct pci_dev *dev)
{ {
......
...@@ -353,6 +353,11 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, ...@@ -353,6 +353,11 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
void pci_enable_acs(struct pci_dev *dev); void pci_enable_acs(struct pci_dev *dev);
/* PCI error reporting and recovery */
void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service);
void pcie_do_nonfatal_recovery(struct pci_dev *dev);
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM #ifdef CONFIG_PCIEASPM
void pcie_aspm_init_link_state(struct pci_dev *pdev); void pcie_aspm_init_link_state(struct pci_dev *pdev);
void pcie_aspm_exit_link_state(struct pci_dev *pdev); void pcie_aspm_exit_link_state(struct pci_dev *pdev);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# Makefile for PCI Express features and port driver # Makefile for PCI Express features and port driver
pcieportdrv-y := portdrv_core.o portdrv_pci.o pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
......
...@@ -94,7 +94,7 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev, ...@@ -94,7 +94,7 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
*/ */
static void aer_enable_rootport(struct aer_rpc *rpc) static void aer_enable_rootport(struct aer_rpc *rpc)
{ {
struct pci_dev *pdev = rpc->rpd->port; struct pci_dev *pdev = rpc->rpd;
int aer_pos; int aer_pos;
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
...@@ -136,7 +136,7 @@ static void aer_enable_rootport(struct aer_rpc *rpc) ...@@ -136,7 +136,7 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
*/ */
static void aer_disable_rootport(struct aer_rpc *rpc) static void aer_disable_rootport(struct aer_rpc *rpc)
{ {
struct pci_dev *pdev = rpc->rpd->port; struct pci_dev *pdev = rpc->rpd;
u32 reg32; u32 reg32;
int pos; int pos;
...@@ -232,7 +232,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) ...@@ -232,7 +232,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
/* Initialize Root lock access, e_lock, to Root Error Status Reg */ /* Initialize Root lock access, e_lock, to Root Error Status Reg */
spin_lock_init(&rpc->e_lock); spin_lock_init(&rpc->e_lock);
rpc->rpd = dev; rpc->rpd = dev->port;
INIT_WORK(&rpc->dpc_handler, aer_isr); INIT_WORK(&rpc->dpc_handler, aer_isr);
mutex_init(&rpc->rpc_mutex); mutex_init(&rpc->rpc_mutex);
...@@ -353,10 +353,7 @@ static void aer_error_resume(struct pci_dev *dev) ...@@ -353,10 +353,7 @@ static void aer_error_resume(struct pci_dev *dev)
pos = dev->aer_cap; pos = dev->aer_cap;
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
if (dev->error_state == pci_channel_io_normal) status &= ~mask; /* Clear corresponding nonfatal bits */
status &= ~mask; /* Clear corresponding nonfatal bits */
else
status &= mask; /* Clear corresponding fatal bits */
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
} }
......
...@@ -58,7 +58,7 @@ struct aer_err_source { ...@@ -58,7 +58,7 @@ struct aer_err_source {
}; };
struct aer_rpc { struct aer_rpc {
struct pcie_device *rpd; /* Root Port device */ struct pci_dev *rpd; /* Root Port device */
struct work_struct dpc_handler; struct work_struct dpc_handler;
struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
struct aer_err_info e_info; struct aer_err_info e_info;
...@@ -76,36 +76,6 @@ struct aer_rpc { ...@@ -76,36 +76,6 @@ struct aer_rpc {
*/ */
}; };
struct aer_broadcast_data {
enum pci_channel_state state;
enum pci_ers_result result;
};
static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
enum pci_ers_result new)
{
if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
return PCI_ERS_RESULT_NO_AER_DRIVER;
if (new == PCI_ERS_RESULT_NONE)
return orig;
switch (orig) {
case PCI_ERS_RESULT_CAN_RECOVER:
case PCI_ERS_RESULT_RECOVERED:
orig = new;
break;
case PCI_ERS_RESULT_DISCONNECT:
if (new == PCI_ERS_RESULT_NEED_RESET)
orig = PCI_ERS_RESULT_NEED_RESET;
break;
default:
break;
}
return orig;
}
extern struct bus_type pcie_port_bus_type; extern struct bus_type pcie_port_bus_type;
void aer_isr(struct work_struct *work); void aer_isr(struct work_struct *work);
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
......
This diff is collapsed.
...@@ -163,17 +163,17 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) ...@@ -163,17 +163,17 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
int id = ((dev->bus->number << 8) | dev->devfn); int id = ((dev->bus->number << 8) | dev->devfn);
if (!info->status) { if (!info->status) {
pci_err(dev, "PCIe Bus Error: severity=%s, type=Unaccessible, id=%04x(Unregistered Agent ID)\n", pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
aer_error_severity_string[info->severity], id); aer_error_severity_string[info->severity]);
goto out; goto out;
} }
layer = AER_GET_LAYER_ERROR(info->severity, info->status); layer = AER_GET_LAYER_ERROR(info->severity, info->status);
agent = AER_GET_AGENT(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status);
pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
aer_error_severity_string[info->severity], aer_error_severity_string[info->severity],
aer_error_layer[layer], id, aer_agent_string[agent]); aer_error_layer[layer], aer_agent_string[agent]);
pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
dev->vendor, dev->device, dev->vendor, dev->device,
...@@ -186,17 +186,21 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) ...@@ -186,17 +186,21 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
out: out:
if (info->id && info->error_dev_num > 1 && info->id == id) if (info->id && info->error_dev_num > 1 && info->id == id)
pci_err(dev, " Error of this Agent(%04x) is reported first\n", id); pci_err(dev, " Error of this Agent is reported first\n");
trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
info->severity); info->severity, info->tlp_header_valid, &info->tlp);
} }
void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
{ {
pci_info(dev, "AER: %s%s error received: id=%04x\n", u8 bus = info->id >> 8;
u8 devfn = info->id & 0xff;
pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n",
info->multi_error_valid ? "Multiple " : "", info->multi_error_valid ? "Multiple " : "",
aer_error_severity_string[info->severity], info->id); aer_error_severity_string[info->severity],
pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
} }
#ifdef CONFIG_ACPI_APEI_PCIEAER #ifdef CONFIG_ACPI_APEI_PCIEAER
...@@ -216,28 +220,30 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer); ...@@ -216,28 +220,30 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
void cper_print_aer(struct pci_dev *dev, int aer_severity, void cper_print_aer(struct pci_dev *dev, int aer_severity,
struct aer_capability_regs *aer) struct aer_capability_regs *aer)
{ {
int layer, agent, status_strs_size, tlp_header_valid = 0; int layer, agent, tlp_header_valid = 0;
u32 status, mask; u32 status, mask;
const char **status_strs; struct aer_err_info info;
if (aer_severity == AER_CORRECTABLE) { if (aer_severity == AER_CORRECTABLE) {
status = aer->cor_status; status = aer->cor_status;
mask = aer->cor_mask; mask = aer->cor_mask;
status_strs = aer_correctable_error_string;
status_strs_size = ARRAY_SIZE(aer_correctable_error_string);
} else { } else {
status = aer->uncor_status; status = aer->uncor_status;
mask = aer->uncor_mask; mask = aer->uncor_mask;
status_strs = aer_uncorrectable_error_string;
status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string);
tlp_header_valid = status & AER_LOG_TLP_MASKS; tlp_header_valid = status & AER_LOG_TLP_MASKS;
} }
layer = AER_GET_LAYER_ERROR(aer_severity, status); layer = AER_GET_LAYER_ERROR(aer_severity, status);
agent = AER_GET_AGENT(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status);
memset(&info, 0, sizeof(info));
info.severity = aer_severity;
info.status = status;
info.mask = mask;
info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
cper_print_bits("", status, status_strs, status_strs_size); __aer_print_error(dev, &info);
pci_err(dev, "aer_layer=%s, aer_agent=%s\n", pci_err(dev, "aer_layer=%s, aer_agent=%s\n",
aer_error_layer[layer], aer_agent_string[agent]); aer_error_layer[layer], aer_agent_string[agent]);
...@@ -249,6 +255,6 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity, ...@@ -249,6 +255,6 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,
__print_tlp_header(dev, &aer->header_log); __print_tlp_header(dev, &aer->header_log);
trace_aer_event(dev_name(&dev->dev), (status & ~mask), trace_aer_event(dev_name(&dev->dev), (status & ~mask),
aer_severity); aer_severity, tlp_header_valid, &aer->header_log);
} }
#endif #endif
...@@ -68,44 +68,35 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) ...@@ -68,44 +68,35 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
static void dpc_wait_link_inactive(struct dpc_dev *dpc) static void dpc_wait_link_inactive(struct dpc_dev *dpc)
{ {
unsigned long timeout = jiffies + HZ;
struct pci_dev *pdev = dpc->dev->port; struct pci_dev *pdev = dpc->dev->port;
struct device *dev = &dpc->dev->device;
u16 lnk_status;
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); pcie_wait_for_link(pdev, false);
while (lnk_status & PCI_EXP_LNKSTA_DLLLA &&
!time_after(jiffies, timeout)) {
msleep(10);
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
}
if (lnk_status & PCI_EXP_LNKSTA_DLLLA)
dev_warn(dev, "Link state not disabled for DPC event\n");
} }
static void dpc_work(struct work_struct *work) static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
{ {
struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); struct dpc_dev *dpc;
struct pci_dev *dev, *temp, *pdev = dpc->dev->port; struct pcie_device *pciedev;
struct pci_bus *parent = pdev->subordinate; struct device *devdpc;
u16 cap = dpc->cap_pos, ctl; u16 cap, ctl;
pci_lock_rescan_remove(); /*
list_for_each_entry_safe_reverse(dev, temp, &parent->devices, * DPC disables the Link automatically in hardware, so it has
bus_list) { * already been reset by the time we get here.
pci_dev_get(dev); */
pci_dev_set_disconnected(dev, NULL); devdpc = pcie_port_find_device(pdev, PCIE_PORT_SERVICE_DPC);
if (pci_has_subordinate(dev)) pciedev = to_pcie_device(devdpc);
pci_walk_bus(dev->subordinate, dpc = get_service_data(pciedev);
pci_dev_set_disconnected, NULL); cap = dpc->cap_pos;
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev); /*
} * Wait until the Link is inactive, then clear DPC Trigger Status
pci_unlock_rescan_remove(); * to allow the Port to leave DPC.
*/
dpc_wait_link_inactive(dpc); dpc_wait_link_inactive(dpc);
if (dpc->rp_extensions && dpc_wait_rp_inactive(dpc)) if (dpc->rp_extensions && dpc_wait_rp_inactive(dpc))
return; return PCI_ERS_RESULT_DISCONNECT;
if (dpc->rp_extensions && dpc->rp_pio_status) { if (dpc->rp_extensions && dpc->rp_pio_status) {
pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS,
dpc->rp_pio_status); dpc->rp_pio_status);
...@@ -118,6 +109,17 @@ static void dpc_work(struct work_struct *work) ...@@ -118,6 +109,17 @@ static void dpc_work(struct work_struct *work)
pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl); pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl);
pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL, pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL,
ctl | PCI_EXP_DPC_CTL_INT_EN); ctl | PCI_EXP_DPC_CTL_INT_EN);
return PCI_ERS_RESULT_RECOVERED;
}
static void dpc_work(struct work_struct *work)
{
struct dpc_dev *dpc = container_of(work, struct dpc_dev, work);
struct pci_dev *pdev = dpc->dev->port;
/* We configure DPC so it only triggers on ERR_FATAL */
pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_DPC);
} }
static void dpc_process_rp_pio_error(struct dpc_dev *dpc) static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
...@@ -270,7 +272,7 @@ static int dpc_probe(struct pcie_device *dev) ...@@ -270,7 +272,7 @@ static int dpc_probe(struct pcie_device *dev)
} }
} }
ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN; ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
...@@ -288,7 +290,7 @@ static void dpc_remove(struct pcie_device *dev) ...@@ -288,7 +290,7 @@ static void dpc_remove(struct pcie_device *dev)
u16 ctl; u16 ctl;
pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
ctl &= ~(PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN); ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN);
pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
} }
...@@ -298,6 +300,7 @@ static struct pcie_port_service_driver dpcdriver = { ...@@ -298,6 +300,7 @@ static struct pcie_port_service_driver dpcdriver = {
.service = PCIE_PORT_SERVICE_DPC, .service = PCIE_PORT_SERVICE_DPC,
.probe = dpc_probe, .probe = dpc_probe,
.remove = dpc_remove, .remove = dpc_remove,
.reset_link = dpc_reset_link,
}; };
static int __init dpc_service_init(void) static int __init dpc_service_init(void)
......
This diff is collapsed.
...@@ -112,4 +112,7 @@ static inline bool pcie_pme_no_msi(void) { return false; } ...@@ -112,4 +112,7 @@ static inline bool pcie_pme_no_msi(void) { return false; }
static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {} static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
#endif /* !CONFIG_PCIE_PME */ #endif /* !CONFIG_PCIE_PME */
struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev,
u32 service);
struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
#endif /* _PORTDRV_H_ */ #endif /* _PORTDRV_H_ */
...@@ -19,6 +19,12 @@ ...@@ -19,6 +19,12 @@
#include "../pci.h" #include "../pci.h"
#include "portdrv.h" #include "portdrv.h"
struct portdrv_service_data {
struct pcie_port_service_driver *drv;
struct device *dev;
u32 service;
};
/** /**
* release_pcie_device - free PCI Express port service device structure * release_pcie_device - free PCI Express port service device structure
* @dev: Port service device to release * @dev: Port service device to release
...@@ -398,6 +404,69 @@ static int remove_iter(struct device *dev, void *data) ...@@ -398,6 +404,69 @@ static int remove_iter(struct device *dev, void *data)
return 0; return 0;
} }
static int find_service_iter(struct device *device, void *data)
{
struct pcie_port_service_driver *service_driver;
struct portdrv_service_data *pdrvs;
u32 service;
pdrvs = (struct portdrv_service_data *) data;
service = pdrvs->service;
if (device->bus == &pcie_port_bus_type && device->driver) {
service_driver = to_service_driver(device->driver);
if (service_driver->service == service) {
pdrvs->drv = service_driver;
pdrvs->dev = device;
return 1;
}
}
return 0;
}
/**
* pcie_port_find_service - find the service driver
* @dev: PCI Express port the service is associated with
* @service: Service to find
*
* Find PCI Express port service driver associated with given service
*/
struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev,
u32 service)
{
struct pcie_port_service_driver *drv;
struct portdrv_service_data pdrvs;
pdrvs.drv = NULL;
pdrvs.service = service;
device_for_each_child(&dev->dev, &pdrvs, find_service_iter);
drv = pdrvs.drv;
return drv;
}
/**
* pcie_port_find_device - find the struct device
* @dev: PCI Express port the service is associated with
* @service: For the service to find
*
* Find the struct device associated with given service on a pci_dev
*/
struct device *pcie_port_find_device(struct pci_dev *dev,
u32 service)
{
struct device *device;
struct portdrv_service_data pdrvs;
pdrvs.dev = NULL;
pdrvs.service = service;
device_for_each_child(&dev->dev, &pdrvs, find_service_iter);
device = pdrvs.dev;
return device;
}
/** /**
* pcie_port_device_remove - unregister PCI Express port service devices * pcie_port_device_remove - unregister PCI Express port service devices
* @dev: PCI Express port the service devices to unregister are associated with * @dev: PCI Express port the service devices to unregister are associated with
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define AER_NONFATAL 0 #define AER_NONFATAL 0
#define AER_FATAL 1 #define AER_FATAL 1
#define AER_CORRECTABLE 2 #define AER_CORRECTABLE 2
#define DPC_FATAL 3
struct pci_dev; struct pci_dev;
......
...@@ -2284,7 +2284,7 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) ...@@ -2284,7 +2284,7 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev)
return false; return false;
} }
#if defined(CONFIG_PCIEAER) || defined(CONFIG_EEH) #if defined(CONFIG_PCIEPORTBUS) || defined(CONFIG_EEH)
void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
#endif #endif
......
...@@ -298,30 +298,44 @@ TRACE_EVENT(non_standard_event, ...@@ -298,30 +298,44 @@ TRACE_EVENT(non_standard_event,
TRACE_EVENT(aer_event, TRACE_EVENT(aer_event,
TP_PROTO(const char *dev_name, TP_PROTO(const char *dev_name,
const u32 status, const u32 status,
const u8 severity), const u8 severity,
const u8 tlp_header_valid,
struct aer_header_log_regs *tlp),
TP_ARGS(dev_name, status, severity), TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
TP_STRUCT__entry( TP_STRUCT__entry(
__string( dev_name, dev_name ) __string( dev_name, dev_name )
__field( u32, status ) __field( u32, status )
__field( u8, severity ) __field( u8, severity )
__field( u8, tlp_header_valid)
__array( u32, tlp_header, 4 )
), ),
TP_fast_assign( TP_fast_assign(
__assign_str(dev_name, dev_name); __assign_str(dev_name, dev_name);
__entry->status = status; __entry->status = status;
__entry->severity = severity; __entry->severity = severity;
__entry->tlp_header_valid = tlp_header_valid;
if (tlp_header_valid) {
__entry->tlp_header[0] = tlp->dw0;
__entry->tlp_header[1] = tlp->dw1;
__entry->tlp_header[2] = tlp->dw2;
__entry->tlp_header[3] = tlp->dw3;
}
), ),
TP_printk("%s PCIe Bus Error: severity=%s, %s\n", TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
__get_str(dev_name), __get_str(dev_name),
__entry->severity == AER_CORRECTABLE ? "Corrected" : __entry->severity == AER_CORRECTABLE ? "Corrected" :
__entry->severity == AER_FATAL ? __entry->severity == AER_FATAL ?
"Fatal" : "Uncorrected, non-fatal", "Fatal" : "Uncorrected, non-fatal",
__entry->severity == AER_CORRECTABLE ? __entry->severity == AER_CORRECTABLE ?
__print_flags(__entry->status, "|", aer_correctable_errors) : __print_flags(__entry->status, "|", aer_correctable_errors) :
__print_flags(__entry->status, "|", aer_uncorrectable_errors)) __print_flags(__entry->status, "|", aer_uncorrectable_errors),
__entry->tlp_header_valid ?
__print_array(__entry->tlp_header, 4, 4) :
"Not available")
); );
/* /*
......
...@@ -981,6 +981,7 @@ ...@@ -981,6 +981,7 @@
#define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ #define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */
#define PCI_EXP_DPC_CTL 6 /* DPC control */ #define PCI_EXP_DPC_CTL 6 /* DPC control */
#define PCI_EXP_DPC_CTL_EN_FATAL 0x0001 /* Enable trigger on ERR_FATAL message */
#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */ #define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */
#define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */ #define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment