⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aerdrv_core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	pci_ers_result_t status;	struct find_aer_service_data data;	if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)		udev = dev;	else		udev= dev->bus->self;	data.is_downstream = 0;	data.aer_driver = NULL;	find_aer_service(udev, &data);	/*	 * Use the aer driver of the error agent firstly.	 * If it hasn't the aer driver, use the root port's	 */	if (!data.aer_driver || !data.aer_driver->reset_link) {		if (data.is_downstream &&			aerdev->device.driver &&			to_service_driver(aerdev->device.driver)->reset_link) {			data.aer_driver =				to_service_driver(aerdev->device.driver);		} else {			printk(KERN_DEBUG "No link-reset support to Device ID"				"[%s]\n",				dev->dev.bus_id);			return PCI_ERS_RESULT_DISCONNECT;		}	}	status = data.aer_driver->reset_link(udev);	if (status != PCI_ERS_RESULT_RECOVERED) {		printk(KERN_DEBUG "Link reset at upstream Device ID"			"[%s] failed\n",			udev->dev.bus_id);		return PCI_ERS_RESULT_DISCONNECT;	}	return status;}/** * do_recovery - handle nonfatal/fatal error recovery process * @aerdev: pointer to a pcie_device data structure of root port * @dev: pointer to a pci_dev data structure of agent detecting an error * @severity: error severity type * * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast * error detected message to all downstream drivers within a hierarchy in * question and return the returned code. */static pci_ers_result_t do_recovery(struct pcie_device *aerdev,		struct pci_dev *dev,		int severity){	pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;	enum pci_channel_state state;	if (severity == AER_FATAL)		state = pci_channel_io_frozen;	else		state = pci_channel_io_normal;	status = broadcast_error_message(dev,			state,			"error_detected",			report_error_detected);	if (severity == AER_FATAL) {		result = reset_link(aerdev, dev);		if (result != PCI_ERS_RESULT_RECOVERED) {			/* TODO: Should panic here? */			return result;		}	}	if (status == PCI_ERS_RESULT_CAN_RECOVER)		status = broadcast_error_message(dev,				state,				"mmio_enabled",				report_mmio_enabled);	if (status == PCI_ERS_RESULT_NEED_RESET) {		/*		 * TODO: Should call platform-specific		 * functions to reset slot before calling		 * drivers' slot_reset callbacks?		 */		status = broadcast_error_message(dev,				state,				"slot_reset",				report_slot_reset);	}	if (status == PCI_ERS_RESULT_RECOVERED)		broadcast_error_message(dev,				state,				"resume",				report_resume);	return status;}/** * handle_error_source - handle logging error into an event log * @aerdev: pointer to pcie_device data structure of the root port * @dev: pointer to pci_dev data structure of error source device * @info: comprehensive error information * * Invoked when an error being detected by Root Port. */static void handle_error_source(struct pcie_device * aerdev,	struct pci_dev *dev,	struct aer_err_info info){	pci_ers_result_t status = 0;	int pos;	if (info.severity == AER_CORRECTABLE) {		/*		 * Correctable error does not need software intevention.		 * No need to go through error recovery process.		 */		pos = pci_find_aer_capability(dev);		if (pos)			pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,					info.status);	} else {		status = do_recovery(aerdev, dev, info.severity);		if (status == PCI_ERS_RESULT_RECOVERED) {			printk(KERN_DEBUG "AER driver successfully recovered\n");		} else {			/* TODO: Should kernel panic here? */			printk(KERN_DEBUG "AER driver didn't recover\n");		}	}}/** * aer_enable_rootport - enable Root Port's interrupts when receiving messages * @rpc: pointer to a Root Port data structure * * Invoked when PCIE bus loads AER service driver. */void aer_enable_rootport(struct aer_rpc *rpc){	struct pci_dev *pdev = rpc->rpd->port;	int pos, aer_pos;	u16 reg16;	u32 reg32;	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);	/* Clear PCIE Capability's Device Status */	pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);	pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);	/* Disable system error generation in response to error messages */	pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);	reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);	pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);	aer_pos = pci_find_aer_capability(pdev);	/* Clear error status */	pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);	pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);	pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);	pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);	pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);	pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);	/* Enable Root Port device reporting error itself */	pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);	reg16 = reg16 |		PCI_EXP_DEVCTL_CERE |		PCI_EXP_DEVCTL_NFERE |		PCI_EXP_DEVCTL_FERE |		PCI_EXP_DEVCTL_URRE;	pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,		reg16);	/* Enable Root Port's interrupt in response to error messages */	pci_write_config_dword(pdev,		aer_pos + PCI_ERR_ROOT_COMMAND,		ROOT_PORT_INTR_ON_MESG_MASK);}/** * disable_root_aer - disable Root Port's interrupts when receiving messages * @rpc: pointer to a Root Port data structure * * Invoked when PCIE bus unloads AER service driver. */static void disable_root_aer(struct aer_rpc *rpc){	struct pci_dev *pdev = rpc->rpd->port;	u32 reg32;	int pos;	pos = pci_find_aer_capability(pdev);	/* Disable Root's interrupt in response to error messages */	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);	/* Clear Root's error status reg */	pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);}/** * get_e_source - retrieve an error source * @rpc: pointer to the root port which holds an error * * Invoked by DPC handler to consume an error. */static struct aer_err_source* get_e_source(struct aer_rpc *rpc){	struct aer_err_source *e_source;	unsigned long flags;	/* Lock access to Root error producer/consumer index */	spin_lock_irqsave(&rpc->e_lock, flags);	if (rpc->prod_idx == rpc->cons_idx) {		spin_unlock_irqrestore(&rpc->e_lock, flags);		return NULL;	}	e_source = &rpc->e_sources[rpc->cons_idx];	rpc->cons_idx++;	if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)		rpc->cons_idx = 0;	spin_unlock_irqrestore(&rpc->e_lock, flags);	return e_source;}static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info){	int pos;	pos = pci_find_aer_capability(dev);	/* The device might not support AER */	if (!pos)		return AER_SUCCESS;	if (info->severity == AER_CORRECTABLE) {		pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,			&info->status);		if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))			return AER_UNSUCCESS;	} else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||		info->severity == AER_NONFATAL) {		/* Link is still healthy for IO reads */		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,			&info->status);		if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))			return AER_UNSUCCESS;		if (info->status & AER_LOG_TLP_MASKS) {			info->flags |= AER_TLP_HEADER_VALID_FLAG;			pci_read_config_dword(dev,				pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);			pci_read_config_dword(dev,				pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);			pci_read_config_dword(dev,				pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);			pci_read_config_dword(dev,				pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);		}	}	return AER_SUCCESS;}/** * aer_isr_one_error - consume an error detected by root port * @p_device: pointer to error root port service device * @e_src: pointer to an error source */static void aer_isr_one_error(struct pcie_device *p_device,		struct aer_err_source *e_src){	struct device *s_device;	struct aer_err_info e_info = {0, 0, 0,};	int i;	u16 id;	/*	 * There is a possibility that both correctable error and	 * uncorrectable error being logged. Report correctable error first.	 */	for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {		if (i > 4)			break;		if (!(e_src->status & i))			continue;		/* Init comprehensive error information */		if (i & PCI_ERR_ROOT_COR_RCV) {			id = ERR_COR_ID(e_src->id);			e_info.severity = AER_CORRECTABLE;		} else {			id = ERR_UNCOR_ID(e_src->id);			e_info.severity = ((e_src->status >> 6) & 1);		}		if (e_src->status &			(PCI_ERR_ROOT_MULTI_COR_RCV |			 PCI_ERR_ROOT_MULTI_UNCOR_RCV))			e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;		if (!(s_device = find_source_device(p_device->port, id))) {			printk(KERN_DEBUG "%s->can't find device of ID%04x\n",				__FUNCTION__, id);			continue;		}		if (get_device_error_info(to_pci_dev(s_device), &e_info) ==				AER_SUCCESS) {			aer_print_error(to_pci_dev(s_device), &e_info);			handle_error_source(p_device,				to_pci_dev(s_device),				e_info);		}	}}/** * aer_isr - consume errors detected by root port * @work: definition of this work item * * Invoked, as DPC, when root port records new detected error */void aer_isr(struct work_struct *work){	struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);	struct pcie_device *p_device = rpc->rpd;	struct aer_err_source *e_src;	mutex_lock(&rpc->rpc_mutex);	e_src = get_e_source(rpc);	while (e_src) {		aer_isr_one_error(p_device, e_src);		e_src = get_e_source(rpc);	}	mutex_unlock(&rpc->rpc_mutex);	wake_up(&rpc->wait_release);}/** * aer_delete_rootport - disable root port aer and delete service data * @rpc: pointer to a root port device being deleted * * Invoked when AER service unloaded on a specific Root Port */void aer_delete_rootport(struct aer_rpc *rpc){	/* Disable root port AER itself */	disable_root_aer(rpc);	kfree(rpc);}/** * aer_init - provide AER initialization * @dev: pointer to AER pcie device * * Invoked when AER service driver is loaded. */int aer_init(struct pcie_device *dev){	if (aer_osc_setup(dev) && !forceload)		return -ENXIO;	return AER_SUCCESS;}EXPORT_SYMBOL_GPL(pci_find_aer_capability);EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);EXPORT_SYMBOL_GPL(pci_cleanup_aer_correct_error_status);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -