]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Mike Mason <mmlnx@us.ibm.com> |
2 | Date: Tue, 10 Feb 2009 11:12:21 +0000 (+0000) | |
3 | Subject: powerpc/eeh: Only disable/enable LSI interrupts in EEH | |
4 | Patch-mainline: 2.6.30-rc1 | |
5 | Git-commit: 8535ef05a6904429ce72671c3035dbf05e6d5edf | |
6 | References: bnc#509497 | |
7 | ||
8 | powerpc/eeh: Only disable/enable LSI interrupts in EEH | |
9 | ||
10 | The EEH code disables and enables interrupts during the | |
11 | device recovery process. This is unnecessary for MSI | |
12 | and MSI-X interrupts because they are effectively disabled | |
13 | by the DMA Stopped state when an EEH error occurs. The | |
14 | current code is also incorrect for MSI-X interrupts. It | |
15 | doesn't take into account that MSI-X interrupts are tracked | |
16 | in a different way than LSI/MSI interrupts. This patch | |
17 | ensures only LSI interrupts are disabled/enabled. | |
18 | ||
19 | Signed-off-by: Mike Mason <mmlnx@us.ibm.com> | |
20 | Acked-by: Linas Vepstas <linasvepstas@gmail.com> | |
21 | Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> | |
22 | Acked-by: Jeff Mahoney <jeffm@suse.com> | |
23 | --- | |
24 | ||
25 | arch/powerpc/platforms/pseries/eeh_driver.c | 68 ++++++++++++++++++---------- | |
26 | 1 file changed, 45 insertions(+), 23 deletions(-) | |
27 | ||
28 | --- a/arch/powerpc/platforms/pseries/eeh_driver.c | |
29 | +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |
30 | @@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq) | |
31 | return rc; | |
32 | } | |
33 | ||
34 | +/** | |
35 | + * eeh_disable_irq - disable interrupt for the recovering device | |
36 | + */ | |
37 | +static void eeh_disable_irq(struct pci_dev *dev) | |
38 | +{ | |
39 | + struct device_node *dn = pci_device_to_OF_node(dev); | |
40 | + | |
41 | + /* Don't disable MSI and MSI-X interrupts. They are | |
42 | + * effectively disabled by the DMA Stopped state | |
43 | + * when an EEH error occurs. | |
44 | + */ | |
45 | + if (dev->msi_enabled || dev->msix_enabled) | |
46 | + return; | |
47 | + | |
48 | + if (!irq_in_use(dev->irq)) | |
49 | + return; | |
50 | + | |
51 | + PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | |
52 | + disable_irq_nosync(dev->irq); | |
53 | +} | |
54 | + | |
55 | +/** | |
56 | + * eeh_enable_irq - enable interrupt for the recovering device | |
57 | + */ | |
58 | +static void eeh_enable_irq(struct pci_dev *dev) | |
59 | +{ | |
60 | + struct device_node *dn = pci_device_to_OF_node(dev); | |
61 | + | |
62 | + if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { | |
63 | + PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; | |
64 | + enable_irq(dev->irq); | |
65 | + } | |
66 | +} | |
67 | + | |
68 | /* ------------------------------------------------------- */ | |
69 | /** | |
70 | * eeh_report_error - report pci error to each device driver | |
71 | @@ -98,11 +132,8 @@ static void eeh_report_error(struct pci_ | |
72 | if (!driver) | |
73 | return; | |
74 | ||
75 | - if (irq_in_use (dev->irq)) { | |
76 | - struct device_node *dn = pci_device_to_OF_node(dev); | |
77 | - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | |
78 | - disable_irq_nosync(dev->irq); | |
79 | - } | |
80 | + eeh_disable_irq(dev); | |
81 | + | |
82 | if (!driver->err_handler || | |
83 | !driver->err_handler->error_detected) | |
84 | return; | |
85 | @@ -147,17 +178,14 @@ static void eeh_report_reset(struct pci_ | |
86 | { | |
87 | enum pci_ers_result rc, *res = userdata; | |
88 | struct pci_driver *driver = dev->driver; | |
89 | - struct device_node *dn = pci_device_to_OF_node(dev); | |
90 | ||
91 | if (!driver) | |
92 | return; | |
93 | ||
94 | dev->error_state = pci_channel_io_normal; | |
95 | ||
96 | - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { | |
97 | - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; | |
98 | - enable_irq(dev->irq); | |
99 | - } | |
100 | + eeh_enable_irq(dev); | |
101 | + | |
102 | if (!driver->err_handler || | |
103 | !driver->err_handler->slot_reset) | |
104 | return; | |
105 | @@ -176,17 +204,14 @@ static void eeh_report_reset(struct pci_ | |
106 | static void eeh_report_resume(struct pci_dev *dev, void *userdata) | |
107 | { | |
108 | struct pci_driver *driver = dev->driver; | |
109 | - struct device_node *dn = pci_device_to_OF_node(dev); | |
110 | ||
111 | dev->error_state = pci_channel_io_normal; | |
112 | ||
113 | if (!driver) | |
114 | return; | |
115 | ||
116 | - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { | |
117 | - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; | |
118 | - enable_irq(dev->irq); | |
119 | - } | |
120 | + eeh_enable_irq(dev); | |
121 | + | |
122 | if (!driver->err_handler || | |
123 | !driver->err_handler->resume) | |
124 | return; | |
125 | @@ -210,15 +235,12 @@ static void eeh_report_failure(struct pc | |
126 | if (!driver) | |
127 | return; | |
128 | ||
129 | - if (irq_in_use (dev->irq)) { | |
130 | - struct device_node *dn = pci_device_to_OF_node(dev); | |
131 | - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | |
132 | - disable_irq_nosync(dev->irq); | |
133 | - } | |
134 | - if (!driver->err_handler) | |
135 | - return; | |
136 | - if (!driver->err_handler->error_detected) | |
137 | + eeh_disable_irq(dev); | |
138 | + | |
139 | + if (!driver->err_handler || | |
140 | + !driver->err_handler->error_detected) | |
141 | return; | |
142 | + | |
143 | driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); | |
144 | } | |
145 |