forked from mirrors/linux
		
	ice: Implement pci_error_handler ops
This patch implements the following pci_error_handler ops: .error_detected = ice_pci_err_detected .slot_reset = ice_pci_err_slot_reset .reset_notify = ice_pci_err_reset_notify .reset_prepare = ice_pci_err_reset_prepare .reset_done = ice_pci_err_reset_done .resume = ice_pci_err_resume Signed-off-by: Brett Creeley <brett.creeley@intel.com> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
		
							parent
							
								
									5abac9d7e1
								
							
						
					
					
						commit
						5995b6d0c6
					
				
					 1 changed files with 151 additions and 0 deletions
				
			
		| 
						 | 
					@ -1004,6 +1004,18 @@ static void ice_service_task_stop(struct ice_pf *pf)
 | 
				
			||||||
	clear_bit(__ICE_SERVICE_SCHED, pf->state);
 | 
						clear_bit(__ICE_SERVICE_SCHED, pf->state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_service_task_restart - restart service task and schedule works
 | 
				
			||||||
 | 
					 * @pf: board private structure
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function is needed for suspend and resume works (e.g WoL scenario)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_service_task_restart(struct ice_pf *pf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						clear_bit(__ICE_SERVICE_DIS, pf->state);
 | 
				
			||||||
 | 
						ice_service_task_schedule(pf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ice_service_timer - timer callback to schedule service task
 | 
					 * ice_service_timer - timer callback to schedule service task
 | 
				
			||||||
 * @t: pointer to timer_list
 | 
					 * @t: pointer to timer_list
 | 
				
			||||||
| 
						 | 
					@ -2395,6 +2407,136 @@ static void ice_remove(struct pci_dev *pdev)
 | 
				
			||||||
	pci_disable_pcie_error_reporting(pdev);
 | 
						pci_disable_pcie_error_reporting(pdev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_pci_err_detected - warning that PCI error has been detected
 | 
				
			||||||
 | 
					 * @pdev: PCI device information struct
 | 
				
			||||||
 | 
					 * @err: the type of PCI error
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Called to warn that something happened on the PCI bus and the error handling
 | 
				
			||||||
 | 
					 * is in progress.  Allows the driver to gracefully prepare/handle PCI errors.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static pci_ers_result_t
 | 
				
			||||||
 | 
					ice_pci_err_detected(struct pci_dev *pdev, enum pci_channel_state err)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_pf *pf = pci_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pf) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "%s: unrecoverable device error %d\n",
 | 
				
			||||||
 | 
								__func__, err);
 | 
				
			||||||
 | 
							return PCI_ERS_RESULT_DISCONNECT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!test_bit(__ICE_SUSPENDED, pf->state)) {
 | 
				
			||||||
 | 
							ice_service_task_stop(pf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) {
 | 
				
			||||||
 | 
								set_bit(__ICE_PFR_REQ, pf->state);
 | 
				
			||||||
 | 
								ice_prepare_for_reset(pf);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return PCI_ERS_RESULT_NEED_RESET;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_pci_err_slot_reset - a PCI slot reset has just happened
 | 
				
			||||||
 | 
					 * @pdev: PCI device information struct
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Called to determine if the driver can recover from the PCI slot reset by
 | 
				
			||||||
 | 
					 * using a register read to determine if the device is recoverable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static pci_ers_result_t ice_pci_err_slot_reset(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_pf *pf = pci_get_drvdata(pdev);
 | 
				
			||||||
 | 
						pci_ers_result_t result;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = pci_enable_device_mem(pdev);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev,
 | 
				
			||||||
 | 
								"Cannot re-enable PCI device after reset, error %d\n",
 | 
				
			||||||
 | 
								err);
 | 
				
			||||||
 | 
							result = PCI_ERS_RESULT_DISCONNECT;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pci_set_master(pdev);
 | 
				
			||||||
 | 
							pci_restore_state(pdev);
 | 
				
			||||||
 | 
							pci_save_state(pdev);
 | 
				
			||||||
 | 
							pci_wake_from_d3(pdev, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Check for life */
 | 
				
			||||||
 | 
							reg = rd32(&pf->hw, GLGEN_RTRIG);
 | 
				
			||||||
 | 
							if (!reg)
 | 
				
			||||||
 | 
								result = PCI_ERS_RESULT_RECOVERED;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								result = PCI_ERS_RESULT_DISCONNECT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = pci_cleanup_aer_uncorrect_error_status(pdev);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							dev_dbg(&pdev->dev,
 | 
				
			||||||
 | 
								"pci_cleanup_aer_uncorrect_error_status failed, error %d\n",
 | 
				
			||||||
 | 
								err);
 | 
				
			||||||
 | 
							/* non-fatal, continue */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_pci_err_resume - restart operations after PCI error recovery
 | 
				
			||||||
 | 
					 * @pdev: PCI device information struct
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Called to allow the driver to bring things back up after PCI error and/or
 | 
				
			||||||
 | 
					 * reset recovery have finished
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_pci_err_resume(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_pf *pf = pci_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pf) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev,
 | 
				
			||||||
 | 
								"%s failed, device is unrecoverable\n", __func__);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (test_bit(__ICE_SUSPENDED, pf->state)) {
 | 
				
			||||||
 | 
							dev_dbg(&pdev->dev, "%s failed to resume normal operations!\n",
 | 
				
			||||||
 | 
								__func__);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ice_do_reset(pf, ICE_RESET_PFR);
 | 
				
			||||||
 | 
						ice_service_task_restart(pf);
 | 
				
			||||||
 | 
						mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_pci_err_reset_prepare - prepare device driver for PCI reset
 | 
				
			||||||
 | 
					 * @pdev: PCI device information struct
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_pci_err_reset_prepare(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_pf *pf = pci_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!test_bit(__ICE_SUSPENDED, pf->state)) {
 | 
				
			||||||
 | 
							ice_service_task_stop(pf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) {
 | 
				
			||||||
 | 
								set_bit(__ICE_PFR_REQ, pf->state);
 | 
				
			||||||
 | 
								ice_prepare_for_reset(pf);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_pci_err_reset_done - PCI reset done, device driver reset can begin
 | 
				
			||||||
 | 
					 * @pdev: PCI device information struct
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_pci_err_reset_done(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ice_pci_err_resume(pdev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ice_pci_tbl - PCI Device ID Table
 | 
					/* ice_pci_tbl - PCI Device ID Table
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Wildcard entries (PCI_ANY_ID) should come last
 | 
					 * Wildcard entries (PCI_ANY_ID) should come last
 | 
				
			||||||
| 
						 | 
					@ -2412,12 +2554,21 @@ static const struct pci_device_id ice_pci_tbl[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(pci, ice_pci_tbl);
 | 
					MODULE_DEVICE_TABLE(pci, ice_pci_tbl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pci_error_handlers ice_pci_err_handler = {
 | 
				
			||||||
 | 
						.error_detected = ice_pci_err_detected,
 | 
				
			||||||
 | 
						.slot_reset = ice_pci_err_slot_reset,
 | 
				
			||||||
 | 
						.reset_prepare = ice_pci_err_reset_prepare,
 | 
				
			||||||
 | 
						.reset_done = ice_pci_err_reset_done,
 | 
				
			||||||
 | 
						.resume = ice_pci_err_resume
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pci_driver ice_driver = {
 | 
					static struct pci_driver ice_driver = {
 | 
				
			||||||
	.name = KBUILD_MODNAME,
 | 
						.name = KBUILD_MODNAME,
 | 
				
			||||||
	.id_table = ice_pci_tbl,
 | 
						.id_table = ice_pci_tbl,
 | 
				
			||||||
	.probe = ice_probe,
 | 
						.probe = ice_probe,
 | 
				
			||||||
	.remove = ice_remove,
 | 
						.remove = ice_remove,
 | 
				
			||||||
	.sriov_configure = ice_sriov_configure,
 | 
						.sriov_configure = ice_sriov_configure,
 | 
				
			||||||
 | 
						.err_handler = &ice_pci_err_handler
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue