diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index f5eb69f532e7..ca140580199c 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -208,6 +208,9 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
208 | * Return true if found. | 208 | * Return true if found. |
209 | * | 209 | * |
210 | * Invoked by DPC when error is detected at the Root Port. | 210 | * Invoked by DPC when error is detected at the Root Port. |
211 | * Caller of this function must set id, severity, and multi_error_valid of | ||
212 | * struct aer_err_info pointed by @e_info properly. This function must fill | ||
213 | * e_info->error_dev_num and e_info->dev[], based on the given information. | ||
211 | */ | 214 | */ |
212 | static bool find_source_device(struct pci_dev *parent, | 215 | static bool find_source_device(struct pci_dev *parent, |
213 | struct aer_err_info *e_info) | 216 | struct aer_err_info *e_info) |
@@ -215,6 +218,9 @@ static bool find_source_device(struct pci_dev *parent, | |||
215 | struct pci_dev *dev = parent; | 218 | struct pci_dev *dev = parent; |
216 | int result; | 219 | int result; |
217 | 220 | ||
221 | /* Must reset in this function */ | ||
222 | e_info->error_dev_num = 0; | ||
223 | |||
218 | /* Is Root Port an agent that sends error message? */ | 224 | /* Is Root Port an agent that sends error message? */ |
219 | result = find_device_iter(dev, e_info); | 225 | result = find_device_iter(dev, e_info); |
220 | if (result) | 226 | if (result) |
@@ -580,11 +586,14 @@ static struct aer_err_source *get_e_source(struct aer_rpc *rpc) | |||
580 | * @info: pointer to structure to store the error record | 586 | * @info: pointer to structure to store the error record |
581 | * | 587 | * |
582 | * Return 1 on success, 0 on error. | 588 | * Return 1 on success, 0 on error. |
589 | * | ||
590 | * Note that @info is reused among all error devices. Clear fields properly. | ||
583 | */ | 591 | */ |
584 | static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) | 592 | static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) |
585 | { | 593 | { |
586 | int pos, temp; | 594 | int pos, temp; |
587 | 595 | ||
596 | /* Must reset in this function */ | ||
588 | info->status = 0; | 597 | info->status = 0; |
589 | info->tlp_header_valid = 0; | 598 | info->tlp_header_valid = 0; |
590 | 599 | ||
@@ -657,11 +666,10 @@ static void aer_isr_one_error(struct pcie_device *p_device, | |||
657 | struct aer_err_source *e_src) | 666 | struct aer_err_source *e_src) |
658 | { | 667 | { |
659 | struct aer_err_info *e_info; | 668 | struct aer_err_info *e_info; |
660 | int i; | ||
661 | 669 | ||
662 | /* struct aer_err_info might be big, so we allocate it with slab */ | 670 | /* struct aer_err_info might be big, so we allocate it with slab */ |
663 | e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL); | 671 | e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL); |
664 | if (e_info == NULL) { | 672 | if (!e_info) { |
665 | dev_printk(KERN_DEBUG, &p_device->port->dev, | 673 | dev_printk(KERN_DEBUG, &p_device->port->dev, |
666 | "Can't allocate mem when processing AER errors\n"); | 674 | "Can't allocate mem when processing AER errors\n"); |
667 | return; | 675 | return; |
@@ -671,26 +679,33 @@ static void aer_isr_one_error(struct pcie_device *p_device, | |||
671 | * There is a possibility that both correctable error and | 679 | * There is a possibility that both correctable error and |
672 | * uncorrectable error being logged. Report correctable error first. | 680 | * uncorrectable error being logged. Report correctable error first. |
673 | */ | 681 | */ |
674 | for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) { | 682 | if (e_src->status & PCI_ERR_ROOT_COR_RCV) { |
675 | if (i > 4) | 683 | e_info->id = ERR_COR_ID(e_src->id); |
676 | break; | 684 | e_info->severity = AER_CORRECTABLE; |
677 | if (!(e_src->status & i)) | 685 | |
678 | continue; | 686 | if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) |
679 | 687 | e_info->multi_error_valid = 1; | |
680 | memset(e_info, 0, sizeof(struct aer_err_info)); | 688 | else |
681 | 689 | e_info->multi_error_valid = 0; | |
682 | /* Init comprehensive error information */ | 690 | |
683 | if (i & PCI_ERR_ROOT_COR_RCV) { | 691 | aer_print_port_info(p_device->port, e_info); |
684 | e_info->id = ERR_COR_ID(e_src->id); | 692 | |
685 | e_info->severity = AER_CORRECTABLE; | 693 | if (find_source_device(p_device->port, e_info)) |
686 | } else { | 694 | aer_process_err_devices(p_device, e_info); |
687 | e_info->id = ERR_UNCOR_ID(e_src->id); | 695 | } |
688 | e_info->severity = ((e_src->status >> 6) & 1); | 696 | |
689 | } | 697 | if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { |
690 | if (e_src->status & | 698 | e_info->id = ERR_UNCOR_ID(e_src->id); |
691 | (PCI_ERR_ROOT_MULTI_COR_RCV | | 699 | |
692 | PCI_ERR_ROOT_MULTI_UNCOR_RCV)) | 700 | if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) |
701 | e_info->severity = AER_FATAL; | ||
702 | else | ||
703 | e_info->severity = AER_NONFATAL; | ||
704 | |||
705 | if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) | ||
693 | e_info->multi_error_valid = 1; | 706 | e_info->multi_error_valid = 1; |
707 | else | ||
708 | e_info->multi_error_valid = 0; | ||
694 | 709 | ||
695 | aer_print_port_info(p_device->port, e_info); | 710 | aer_print_port_info(p_device->port, e_info); |
696 | 711 | ||