diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_cache.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 55 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 50 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 182 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/rtasd.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/scanlog.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/vio.c | 274 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 25 |
10 files changed, 169 insertions, 442 deletions
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 930898635c9f..e5e0ff466904 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -1,8 +1,11 @@ | |||
1 | ifeq ($(CONFIG_PPC64),y) | ||
2 | EXTRA_CFLAGS += -mno-minimal-toc | ||
3 | endif | ||
4 | |||
1 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ | 5 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ |
2 | setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ | 6 | setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ |
3 | firmware.o | 7 | firmware.o |
4 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
5 | obj-$(CONFIG_IBMVIO) += vio.o | ||
6 | obj-$(CONFIG_XICS) += xics.o | 9 | obj-$(CONFIG_XICS) += xics.o |
7 | obj-$(CONFIG_SCANLOG) += scanlog.o | 10 | obj-$(CONFIG_SCANLOG) += scanlog.o |
8 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o | 11 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o |
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index d4a402c5866c..98c23aec85be 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c | |||
@@ -304,6 +304,8 @@ void __init pci_addr_cache_build(void) | |||
304 | pci_addr_cache_insert_device(dev); | 304 | pci_addr_cache_insert_device(dev); |
305 | 305 | ||
306 | dn = pci_device_to_OF_node(dev); | 306 | dn = pci_device_to_OF_node(dev); |
307 | if (!dn) | ||
308 | continue; | ||
307 | pci_dev_get (dev); /* matching put is in eeh_remove_device() */ | 309 | pci_dev_get (dev); /* matching put is in eeh_remove_device() */ |
308 | PCI_DN(dn)->pcidev = dev; | 310 | PCI_DN(dn)->pcidev = dev; |
309 | } | 311 | } |
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1fba695e32e8..0ec9a5445b95 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -23,9 +23,8 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/irq.h> | ||
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
28 | #include <linux/notifier.h> | 27 | #include <linux/irq.h> |
29 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
30 | #include <asm/eeh.h> | 29 | #include <asm/eeh.h> |
31 | #include <asm/eeh_event.h> | 30 | #include <asm/eeh_event.h> |
@@ -202,7 +201,11 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata) | |||
202 | 201 | ||
203 | static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | 202 | static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) |
204 | { | 203 | { |
205 | int rc; | 204 | int cnt, rc; |
205 | |||
206 | /* pcibios will clear the counter; save the value */ | ||
207 | cnt = pe_dn->eeh_freeze_count; | ||
208 | |||
206 | if (bus) | 209 | if (bus) |
207 | pcibios_remove_pci_devices(bus); | 210 | pcibios_remove_pci_devices(bus); |
208 | 211 | ||
@@ -241,6 +244,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
241 | ssleep (5); | 244 | ssleep (5); |
242 | pcibios_add_pci_devices(bus); | 245 | pcibios_add_pci_devices(bus); |
243 | } | 246 | } |
247 | pe_dn->eeh_freeze_count = cnt; | ||
244 | 248 | ||
245 | return 0; | 249 | return 0; |
246 | } | 250 | } |
@@ -250,23 +254,29 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
250 | */ | 254 | */ |
251 | #define MAX_WAIT_FOR_RECOVERY 15 | 255 | #define MAX_WAIT_FOR_RECOVERY 15 |
252 | 256 | ||
253 | void handle_eeh_events (struct eeh_event *event) | 257 | struct pci_dn * handle_eeh_events (struct eeh_event *event) |
254 | { | 258 | { |
255 | struct device_node *frozen_dn; | 259 | struct device_node *frozen_dn; |
256 | struct pci_dn *frozen_pdn; | 260 | struct pci_dn *frozen_pdn; |
257 | struct pci_bus *frozen_bus; | 261 | struct pci_bus *frozen_bus; |
258 | int rc = 0; | 262 | int rc = 0; |
259 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; | 263 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; |
260 | const char *pci_str, *drv_str; | 264 | const char *location, *pci_str, *drv_str; |
261 | 265 | ||
262 | frozen_dn = find_device_pe(event->dn); | 266 | frozen_dn = find_device_pe(event->dn); |
263 | frozen_bus = pcibios_find_pci_bus(frozen_dn); | 267 | frozen_bus = pcibios_find_pci_bus(frozen_dn); |
264 | 268 | ||
265 | if (!frozen_dn) { | 269 | if (!frozen_dn) { |
266 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint for %s\n", | 270 | |
267 | pci_name(event->dev)); | 271 | location = (char *) get_property(event->dn, "ibm,loc-code", NULL); |
268 | return; | 272 | location = location ? location : "unknown"; |
273 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " | ||
274 | "for location=%s pci addr=%s\n", | ||
275 | location, pci_name(event->dev)); | ||
276 | return NULL; | ||
269 | } | 277 | } |
278 | location = (char *) get_property(frozen_dn, "ibm,loc-code", NULL); | ||
279 | location = location ? location : "unknown"; | ||
270 | 280 | ||
271 | /* There are two different styles for coming up with the PE. | 281 | /* There are two different styles for coming up with the PE. |
272 | * In the old style, it was the highest EEH-capable device | 282 | * In the old style, it was the highest EEH-capable device |
@@ -278,9 +288,10 @@ void handle_eeh_events (struct eeh_event *event) | |||
278 | frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); | 288 | frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); |
279 | 289 | ||
280 | if (!frozen_bus) { | 290 | if (!frozen_bus) { |
281 | printk(KERN_ERR "EEH: Cannot find PCI bus for %s\n", | 291 | printk(KERN_ERR "EEH: Cannot find PCI bus " |
282 | frozen_dn->full_name); | 292 | "for location=%s dn=%s\n", |
283 | return; | 293 | location, frozen_dn->full_name); |
294 | return NULL; | ||
284 | } | 295 | } |
285 | 296 | ||
286 | #if 0 | 297 | #if 0 |
@@ -314,8 +325,9 @@ void handle_eeh_events (struct eeh_event *event) | |||
314 | 325 | ||
315 | eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */); | 326 | eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */); |
316 | printk(KERN_WARNING | 327 | printk(KERN_WARNING |
317 | "EEH: This PCI device has failed %d times since last reboot: %s - %s\n", | 328 | "EEH: This PCI device has failed %d times since last reboot: " |
318 | frozen_pdn->eeh_freeze_count, drv_str, pci_str); | 329 | "location=%s driver=%s pci addr=%s\n", |
330 | frozen_pdn->eeh_freeze_count, location, drv_str, pci_str); | ||
319 | 331 | ||
320 | /* Walk the various device drivers attached to this slot through | 332 | /* Walk the various device drivers attached to this slot through |
321 | * a reset sequence, giving each an opportunity to do what it needs | 333 | * a reset sequence, giving each an opportunity to do what it needs |
@@ -355,7 +367,7 @@ void handle_eeh_events (struct eeh_event *event) | |||
355 | /* Tell all device drivers that they can resume operations */ | 367 | /* Tell all device drivers that they can resume operations */ |
356 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); | 368 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); |
357 | 369 | ||
358 | return; | 370 | return frozen_pdn; |
359 | 371 | ||
360 | excess_failures: | 372 | excess_failures: |
361 | /* | 373 | /* |
@@ -364,17 +376,18 @@ excess_failures: | |||
364 | * due to actual, failed cards. | 376 | * due to actual, failed cards. |
365 | */ | 377 | */ |
366 | printk(KERN_ERR | 378 | printk(KERN_ERR |
367 | "EEH: PCI device %s - %s has failed %d times \n" | 379 | "EEH: PCI device at location=%s driver=%s pci addr=%s \n" |
368 | "and has been permanently disabled. Please try reseating\n" | 380 | "has failed %d times and has been permanently disabled. \n" |
369 | "this device or replacing it.\n", | 381 | "Please try reseating this device or replacing it.\n", |
370 | drv_str, pci_str, frozen_pdn->eeh_freeze_count); | 382 | location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); |
371 | goto perm_error; | 383 | goto perm_error; |
372 | 384 | ||
373 | hard_fail: | 385 | hard_fail: |
374 | printk(KERN_ERR | 386 | printk(KERN_ERR |
375 | "EEH: Unable to recover from failure of PCI device %s - %s\n" | 387 | "EEH: Unable to recover from failure of PCI device " |
388 | "at location=%s driver=%s pci addr=%s \n" | ||
376 | "Please try reseating this device or replacing it.\n", | 389 | "Please try reseating this device or replacing it.\n", |
377 | drv_str, pci_str); | 390 | location, drv_str, pci_str); |
378 | 391 | ||
379 | perm_error: | 392 | perm_error: |
380 | eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */); | 393 | eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */); |
@@ -384,6 +397,8 @@ perm_error: | |||
384 | 397 | ||
385 | /* Shut down the device drivers for good. */ | 398 | /* Shut down the device drivers for good. */ |
386 | pcibios_remove_pci_devices(frozen_bus); | 399 | pcibios_remove_pci_devices(frozen_bus); |
400 | |||
401 | return NULL; | ||
387 | } | 402 | } |
388 | 403 | ||
389 | /* ---------- end of file ---------- */ | 404 | /* ---------- end of file ---------- */ |
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 40020c65c89e..8f2d12935b99 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Copyright (c) 2005 Linas Vepstas <linas@linas.org> | 18 | * Copyright (c) 2005 Linas Vepstas <linas@linas.org> |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/delay.h> | ||
21 | #include <linux/list.h> | 22 | #include <linux/list.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
23 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
@@ -56,38 +57,43 @@ static int eeh_event_handler(void * dummy) | |||
56 | { | 57 | { |
57 | unsigned long flags; | 58 | unsigned long flags; |
58 | struct eeh_event *event; | 59 | struct eeh_event *event; |
60 | struct pci_dn *pdn; | ||
59 | 61 | ||
60 | daemonize ("eehd"); | 62 | daemonize ("eehd"); |
63 | set_current_state(TASK_INTERRUPTIBLE); | ||
61 | 64 | ||
62 | while (1) { | 65 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
63 | set_current_state(TASK_INTERRUPTIBLE); | 66 | event = NULL; |
64 | 67 | ||
65 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 68 | /* Unqueue the event, get ready to process. */ |
66 | event = NULL; | 69 | if (!list_empty(&eeh_eventlist)) { |
70 | event = list_entry(eeh_eventlist.next, struct eeh_event, list); | ||
71 | list_del(&event->list); | ||
72 | } | ||
73 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
67 | 74 | ||
68 | /* Unqueue the event, get ready to process. */ | 75 | if (event == NULL) |
69 | if (!list_empty(&eeh_eventlist)) { | 76 | return 0; |
70 | event = list_entry(eeh_eventlist.next, struct eeh_event, list); | ||
71 | list_del(&event->list); | ||
72 | } | ||
73 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
74 | 77 | ||
75 | if (event == NULL) | 78 | /* Serialize processing of EEH events */ |
76 | break; | 79 | mutex_lock(&eeh_event_mutex); |
80 | eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); | ||
77 | 81 | ||
78 | /* Serialize processing of EEH events */ | 82 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", |
79 | mutex_lock(&eeh_event_mutex); | 83 | pci_name(event->dev)); |
80 | eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); | ||
81 | 84 | ||
82 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", | 85 | pdn = handle_eeh_events(event); |
83 | pci_name(event->dev)); | ||
84 | 86 | ||
85 | handle_eeh_events(event); | 87 | eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); |
88 | pci_dev_put(event->dev); | ||
89 | kfree(event); | ||
90 | mutex_unlock(&eeh_event_mutex); | ||
86 | 91 | ||
87 | eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); | 92 | /* If there are no new errors after an hour, clear the counter. */ |
88 | pci_dev_put(event->dev); | 93 | if (pdn && pdn->eeh_freeze_count>0) { |
89 | kfree(event); | 94 | msleep_interruptible (3600*1000); |
90 | mutex_unlock(&eeh_event_mutex); | 95 | if (pdn->eeh_freeze_count>0) |
96 | pdn->eeh_freeze_count--; | ||
91 | } | 97 | } |
92 | 98 | ||
93 | return 0; | 99 | return 0; |
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 2643078433f0..d03a8b078f9d 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -1,23 +1,24 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation | 2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation |
3 | * | 3 | * |
4 | * Rewrite, cleanup: | 4 | * Rewrite, cleanup: |
5 | * | 5 | * |
6 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation | 6 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation |
7 | * Copyright (C) 2006 Olof Johansson <olof@lixom.net> | ||
7 | * | 8 | * |
8 | * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR. | 9 | * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR. |
9 | * | 10 | * |
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 14 | * the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. | 15 | * (at your option) any later version. |
15 | * | 16 | * |
16 | * This program is distributed in the hope that it will be useful, | 17 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
20 | * | 21 | * |
21 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
@@ -49,52 +50,46 @@ | |||
49 | 50 | ||
50 | #define DBG(fmt...) | 51 | #define DBG(fmt...) |
51 | 52 | ||
52 | static void tce_build_pSeries(struct iommu_table *tbl, long index, | 53 | static void tce_build_pSeries(struct iommu_table *tbl, long index, |
53 | long npages, unsigned long uaddr, | 54 | long npages, unsigned long uaddr, |
54 | enum dma_data_direction direction) | 55 | enum dma_data_direction direction) |
55 | { | 56 | { |
56 | union tce_entry t; | 57 | u64 proto_tce; |
57 | union tce_entry *tp; | 58 | u64 *tcep; |
59 | u64 rpn; | ||
58 | 60 | ||
59 | index <<= TCE_PAGE_FACTOR; | 61 | index <<= TCE_PAGE_FACTOR; |
60 | npages <<= TCE_PAGE_FACTOR; | 62 | npages <<= TCE_PAGE_FACTOR; |
61 | 63 | ||
62 | t.te_word = 0; | 64 | proto_tce = TCE_PCI_READ; // Read allowed |
63 | t.te_rdwr = 1; // Read allowed | ||
64 | 65 | ||
65 | if (direction != DMA_TO_DEVICE) | 66 | if (direction != DMA_TO_DEVICE) |
66 | t.te_pciwr = 1; | 67 | proto_tce |= TCE_PCI_WRITE; |
67 | 68 | ||
68 | tp = ((union tce_entry *)tbl->it_base) + index; | 69 | tcep = ((u64 *)tbl->it_base) + index; |
69 | 70 | ||
70 | while (npages--) { | 71 | while (npages--) { |
71 | /* can't move this out since we might cross LMB boundary */ | 72 | /* can't move this out since we might cross LMB boundary */ |
72 | t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; | 73 | rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; |
73 | 74 | *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; | |
74 | tp->te_word = t.te_word; | ||
75 | 75 | ||
76 | uaddr += TCE_PAGE_SIZE; | 76 | uaddr += TCE_PAGE_SIZE; |
77 | tp++; | 77 | tcep++; |
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | 81 | ||
82 | static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) | 82 | static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) |
83 | { | 83 | { |
84 | union tce_entry t; | 84 | u64 *tcep; |
85 | union tce_entry *tp; | ||
86 | 85 | ||
87 | npages <<= TCE_PAGE_FACTOR; | 86 | npages <<= TCE_PAGE_FACTOR; |
88 | index <<= TCE_PAGE_FACTOR; | 87 | index <<= TCE_PAGE_FACTOR; |
89 | 88 | ||
90 | t.te_word = 0; | 89 | tcep = ((u64 *)tbl->it_base) + index; |
91 | tp = ((union tce_entry *)tbl->it_base) + index; | 90 | |
92 | 91 | while (npages--) | |
93 | while (npages--) { | 92 | *(tcep++) = 0; |
94 | tp->te_word = t.te_word; | ||
95 | |||
96 | tp++; | ||
97 | } | ||
98 | } | 93 | } |
99 | 94 | ||
100 | 95 | ||
@@ -103,43 +98,44 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
103 | enum dma_data_direction direction) | 98 | enum dma_data_direction direction) |
104 | { | 99 | { |
105 | u64 rc; | 100 | u64 rc; |
106 | union tce_entry tce; | 101 | u64 proto_tce, tce; |
102 | u64 rpn; | ||
107 | 103 | ||
108 | tcenum <<= TCE_PAGE_FACTOR; | 104 | tcenum <<= TCE_PAGE_FACTOR; |
109 | npages <<= TCE_PAGE_FACTOR; | 105 | npages <<= TCE_PAGE_FACTOR; |
110 | 106 | ||
111 | tce.te_word = 0; | 107 | rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; |
112 | tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; | 108 | proto_tce = TCE_PCI_READ; |
113 | tce.te_rdwr = 1; | ||
114 | if (direction != DMA_TO_DEVICE) | 109 | if (direction != DMA_TO_DEVICE) |
115 | tce.te_pciwr = 1; | 110 | proto_tce |= TCE_PCI_WRITE; |
116 | 111 | ||
117 | while (npages--) { | 112 | while (npages--) { |
118 | rc = plpar_tce_put((u64)tbl->it_index, | 113 | tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; |
119 | (u64)tcenum << 12, | 114 | rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce); |
120 | tce.te_word ); | 115 | |
121 | |||
122 | if (rc && printk_ratelimit()) { | 116 | if (rc && printk_ratelimit()) { |
123 | printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); | 117 | printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); |
124 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); | 118 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); |
125 | printk("\ttcenum = 0x%lx\n", (u64)tcenum); | 119 | printk("\ttcenum = 0x%lx\n", (u64)tcenum); |
126 | printk("\ttce val = 0x%lx\n", tce.te_word ); | 120 | printk("\ttce val = 0x%lx\n", tce ); |
127 | show_stack(current, (unsigned long *)__get_SP()); | 121 | show_stack(current, (unsigned long *)__get_SP()); |
128 | } | 122 | } |
129 | 123 | ||
130 | tcenum++; | 124 | tcenum++; |
131 | tce.te_rpn++; | 125 | rpn++; |
132 | } | 126 | } |
133 | } | 127 | } |
134 | 128 | ||
135 | static DEFINE_PER_CPU(void *, tce_page) = NULL; | 129 | static DEFINE_PER_CPU(u64 *, tce_page) = NULL; |
136 | 130 | ||
137 | static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | 131 | static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, |
138 | long npages, unsigned long uaddr, | 132 | long npages, unsigned long uaddr, |
139 | enum dma_data_direction direction) | 133 | enum dma_data_direction direction) |
140 | { | 134 | { |
141 | u64 rc; | 135 | u64 rc; |
142 | union tce_entry tce, *tcep; | 136 | u64 proto_tce; |
137 | u64 *tcep; | ||
138 | u64 rpn; | ||
143 | long l, limit; | 139 | long l, limit; |
144 | 140 | ||
145 | if (TCE_PAGE_FACTOR == 0 && npages == 1) | 141 | if (TCE_PAGE_FACTOR == 0 && npages == 1) |
@@ -152,7 +148,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
152 | * from iommu_alloc{,_sg}() | 148 | * from iommu_alloc{,_sg}() |
153 | */ | 149 | */ |
154 | if (!tcep) { | 150 | if (!tcep) { |
155 | tcep = (void *)__get_free_page(GFP_ATOMIC); | 151 | tcep = (u64 *)__get_free_page(GFP_ATOMIC); |
156 | /* If allocation fails, fall back to the loop implementation */ | 152 | /* If allocation fails, fall back to the loop implementation */ |
157 | if (!tcep) | 153 | if (!tcep) |
158 | return tce_build_pSeriesLP(tbl, tcenum, npages, | 154 | return tce_build_pSeriesLP(tbl, tcenum, npages, |
@@ -163,11 +159,10 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
163 | tcenum <<= TCE_PAGE_FACTOR; | 159 | tcenum <<= TCE_PAGE_FACTOR; |
164 | npages <<= TCE_PAGE_FACTOR; | 160 | npages <<= TCE_PAGE_FACTOR; |
165 | 161 | ||
166 | tce.te_word = 0; | 162 | rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; |
167 | tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; | 163 | proto_tce = TCE_PCI_READ; |
168 | tce.te_rdwr = 1; | ||
169 | if (direction != DMA_TO_DEVICE) | 164 | if (direction != DMA_TO_DEVICE) |
170 | tce.te_pciwr = 1; | 165 | proto_tce |= TCE_PCI_WRITE; |
171 | 166 | ||
172 | /* We can map max one pageful of TCEs at a time */ | 167 | /* We can map max one pageful of TCEs at a time */ |
173 | do { | 168 | do { |
@@ -175,11 +170,11 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
175 | * Set up the page with TCE data, looping through and setting | 170 | * Set up the page with TCE data, looping through and setting |
176 | * the values. | 171 | * the values. |
177 | */ | 172 | */ |
178 | limit = min_t(long, npages, 4096/sizeof(union tce_entry)); | 173 | limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE); |
179 | 174 | ||
180 | for (l = 0; l < limit; l++) { | 175 | for (l = 0; l < limit; l++) { |
181 | tcep[l] = tce; | 176 | tcep[l] = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; |
182 | tce.te_rpn++; | 177 | rpn++; |
183 | } | 178 | } |
184 | 179 | ||
185 | rc = plpar_tce_put_indirect((u64)tbl->it_index, | 180 | rc = plpar_tce_put_indirect((u64)tbl->it_index, |
@@ -195,7 +190,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
195 | printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); | 190 | printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); |
196 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); | 191 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); |
197 | printk("\tnpages = 0x%lx\n", (u64)npages); | 192 | printk("\tnpages = 0x%lx\n", (u64)npages); |
198 | printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word); | 193 | printk("\ttce[0] val = 0x%lx\n", tcep[0]); |
199 | show_stack(current, (unsigned long *)__get_SP()); | 194 | show_stack(current, (unsigned long *)__get_SP()); |
200 | } | 195 | } |
201 | } | 196 | } |
@@ -203,23 +198,17 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, | |||
203 | static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) | 198 | static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) |
204 | { | 199 | { |
205 | u64 rc; | 200 | u64 rc; |
206 | union tce_entry tce; | ||
207 | 201 | ||
208 | tcenum <<= TCE_PAGE_FACTOR; | 202 | tcenum <<= TCE_PAGE_FACTOR; |
209 | npages <<= TCE_PAGE_FACTOR; | 203 | npages <<= TCE_PAGE_FACTOR; |
210 | 204 | ||
211 | tce.te_word = 0; | ||
212 | |||
213 | while (npages--) { | 205 | while (npages--) { |
214 | rc = plpar_tce_put((u64)tbl->it_index, | 206 | rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0); |
215 | (u64)tcenum << 12, | ||
216 | tce.te_word); | ||
217 | 207 | ||
218 | if (rc && printk_ratelimit()) { | 208 | if (rc && printk_ratelimit()) { |
219 | printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); | 209 | printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); |
220 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); | 210 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); |
221 | printk("\ttcenum = 0x%lx\n", (u64)tcenum); | 211 | printk("\ttcenum = 0x%lx\n", (u64)tcenum); |
222 | printk("\ttce val = 0x%lx\n", tce.te_word ); | ||
223 | show_stack(current, (unsigned long *)__get_SP()); | 212 | show_stack(current, (unsigned long *)__get_SP()); |
224 | } | 213 | } |
225 | 214 | ||
@@ -231,31 +220,24 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages | |||
231 | static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) | 220 | static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) |
232 | { | 221 | { |
233 | u64 rc; | 222 | u64 rc; |
234 | union tce_entry tce; | ||
235 | 223 | ||
236 | tcenum <<= TCE_PAGE_FACTOR; | 224 | tcenum <<= TCE_PAGE_FACTOR; |
237 | npages <<= TCE_PAGE_FACTOR; | 225 | npages <<= TCE_PAGE_FACTOR; |
238 | 226 | ||
239 | tce.te_word = 0; | 227 | rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages); |
240 | |||
241 | rc = plpar_tce_stuff((u64)tbl->it_index, | ||
242 | (u64)tcenum << 12, | ||
243 | tce.te_word, | ||
244 | npages); | ||
245 | 228 | ||
246 | if (rc && printk_ratelimit()) { | 229 | if (rc && printk_ratelimit()) { |
247 | printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); | 230 | printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); |
248 | printk("\trc = %ld\n", rc); | 231 | printk("\trc = %ld\n", rc); |
249 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); | 232 | printk("\tindex = 0x%lx\n", (u64)tbl->it_index); |
250 | printk("\tnpages = 0x%lx\n", (u64)npages); | 233 | printk("\tnpages = 0x%lx\n", (u64)npages); |
251 | printk("\ttce val = 0x%lx\n", tce.te_word ); | ||
252 | show_stack(current, (unsigned long *)__get_SP()); | 234 | show_stack(current, (unsigned long *)__get_SP()); |
253 | } | 235 | } |
254 | } | 236 | } |
255 | 237 | ||
256 | static void iommu_table_setparms(struct pci_controller *phb, | 238 | static void iommu_table_setparms(struct pci_controller *phb, |
257 | struct device_node *dn, | 239 | struct device_node *dn, |
258 | struct iommu_table *tbl) | 240 | struct iommu_table *tbl) |
259 | { | 241 | { |
260 | struct device_node *node; | 242 | struct device_node *node; |
261 | unsigned long *basep; | 243 | unsigned long *basep; |
@@ -275,16 +257,16 @@ static void iommu_table_setparms(struct pci_controller *phb, | |||
275 | memset((void *)tbl->it_base, 0, *sizep); | 257 | memset((void *)tbl->it_base, 0, *sizep); |
276 | 258 | ||
277 | tbl->it_busno = phb->bus->number; | 259 | tbl->it_busno = phb->bus->number; |
278 | 260 | ||
279 | /* Units of tce entries */ | 261 | /* Units of tce entries */ |
280 | tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; | 262 | tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; |
281 | 263 | ||
282 | /* Test if we are going over 2GB of DMA space */ | 264 | /* Test if we are going over 2GB of DMA space */ |
283 | if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { | 265 | if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { |
284 | udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); | 266 | udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); |
285 | panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); | 267 | panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); |
286 | } | 268 | } |
287 | 269 | ||
288 | phb->dma_window_base_cur += phb->dma_window_size; | 270 | phb->dma_window_base_cur += phb->dma_window_size; |
289 | 271 | ||
290 | /* Set the tce table size - measured in entries */ | 272 | /* Set the tce table size - measured in entries */ |
@@ -299,30 +281,22 @@ static void iommu_table_setparms(struct pci_controller *phb, | |||
299 | * iommu_table_setparms_lpar | 281 | * iommu_table_setparms_lpar |
300 | * | 282 | * |
301 | * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. | 283 | * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. |
302 | * | ||
303 | * ToDo: properly interpret the ibm,dma-window property. The definition is: | ||
304 | * logical-bus-number (1 word) | ||
305 | * phys-address (#address-cells words) | ||
306 | * size (#cell-size words) | ||
307 | * | ||
308 | * Currently we hard code these sizes (more or less). | ||
309 | */ | 284 | */ |
310 | static void iommu_table_setparms_lpar(struct pci_controller *phb, | 285 | static void iommu_table_setparms_lpar(struct pci_controller *phb, |
311 | struct device_node *dn, | 286 | struct device_node *dn, |
312 | struct iommu_table *tbl, | 287 | struct iommu_table *tbl, |
313 | unsigned int *dma_window) | 288 | unsigned char *dma_window) |
314 | { | 289 | { |
290 | unsigned long offset, size; | ||
291 | |||
315 | tbl->it_busno = PCI_DN(dn)->bussubno; | 292 | tbl->it_busno = PCI_DN(dn)->bussubno; |
293 | of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); | ||
316 | 294 | ||
317 | /* TODO: Parse field size properties properly. */ | ||
318 | tbl->it_size = (((unsigned long)dma_window[4] << 32) | | ||
319 | (unsigned long)dma_window[5]) >> PAGE_SHIFT; | ||
320 | tbl->it_offset = (((unsigned long)dma_window[2] << 32) | | ||
321 | (unsigned long)dma_window[3]) >> PAGE_SHIFT; | ||
322 | tbl->it_base = 0; | 295 | tbl->it_base = 0; |
323 | tbl->it_index = dma_window[0]; | ||
324 | tbl->it_blocksize = 16; | 296 | tbl->it_blocksize = 16; |
325 | tbl->it_type = TCE_PCI; | 297 | tbl->it_type = TCE_PCI; |
298 | tbl->it_offset = offset >> PAGE_SHIFT; | ||
299 | tbl->it_size = size >> PAGE_SHIFT; | ||
326 | } | 300 | } |
327 | 301 | ||
328 | static void iommu_bus_setup_pSeries(struct pci_bus *bus) | 302 | static void iommu_bus_setup_pSeries(struct pci_bus *bus) |
@@ -357,13 +331,9 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus) | |||
357 | if (isa_dn_orig) | 331 | if (isa_dn_orig) |
358 | of_node_put(isa_dn_orig); | 332 | of_node_put(isa_dn_orig); |
359 | 333 | ||
360 | /* Count number of direct PCI children of the PHB. | 334 | /* Count number of direct PCI children of the PHB. */ |
361 | * All PCI device nodes have class-code property, so it's | ||
362 | * an easy way to find them. | ||
363 | */ | ||
364 | for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) | 335 | for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) |
365 | if (get_property(tmp, "class-code", NULL)) | 336 | children++; |
366 | children++; | ||
367 | 337 | ||
368 | DBG("Children: %d\n", children); | 338 | DBG("Children: %d\n", children); |
369 | 339 | ||
@@ -394,10 +364,11 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus) | |||
394 | pci->phb->dma_window_size = 0x8000000ul; | 364 | pci->phb->dma_window_size = 0x8000000ul; |
395 | pci->phb->dma_window_base_cur = 0x8000000ul; | 365 | pci->phb->dma_window_base_cur = 0x8000000ul; |
396 | 366 | ||
397 | tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | 367 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
368 | pci->phb->node); | ||
398 | 369 | ||
399 | iommu_table_setparms(pci->phb, dn, tbl); | 370 | iommu_table_setparms(pci->phb, dn, tbl); |
400 | pci->iommu_table = iommu_init_table(tbl); | 371 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); |
401 | 372 | ||
402 | /* Divide the rest (1.75GB) among the children */ | 373 | /* Divide the rest (1.75GB) among the children */ |
403 | pci->phb->dma_window_size = 0x80000000ul; | 374 | pci->phb->dma_window_size = 0x80000000ul; |
@@ -414,7 +385,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) | |||
414 | struct iommu_table *tbl; | 385 | struct iommu_table *tbl; |
415 | struct device_node *dn, *pdn; | 386 | struct device_node *dn, *pdn; |
416 | struct pci_dn *ppci; | 387 | struct pci_dn *ppci; |
417 | unsigned int *dma_window = NULL; | 388 | unsigned char *dma_window = NULL; |
418 | 389 | ||
419 | DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self); | 390 | DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self); |
420 | 391 | ||
@@ -422,7 +393,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) | |||
422 | 393 | ||
423 | /* Find nearest ibm,dma-window, walking up the device tree */ | 394 | /* Find nearest ibm,dma-window, walking up the device tree */ |
424 | for (pdn = dn; pdn != NULL; pdn = pdn->parent) { | 395 | for (pdn = dn; pdn != NULL; pdn = pdn->parent) { |
425 | dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL); | 396 | dma_window = get_property(pdn, "ibm,dma-window", NULL); |
426 | if (dma_window != NULL) | 397 | if (dma_window != NULL) |
427 | break; | 398 | break; |
428 | } | 399 | } |
@@ -440,12 +411,12 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) | |||
440 | 411 | ||
441 | ppci->bussubno = bus->number; | 412 | ppci->bussubno = bus->number; |
442 | 413 | ||
443 | tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), | 414 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
444 | GFP_KERNEL); | 415 | ppci->phb->node); |
445 | 416 | ||
446 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); | 417 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); |
447 | 418 | ||
448 | ppci->iommu_table = iommu_init_table(tbl); | 419 | ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); |
449 | } | 420 | } |
450 | 421 | ||
451 | if (pdn != dn) | 422 | if (pdn != dn) |
@@ -468,9 +439,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev) | |||
468 | */ | 439 | */ |
469 | if (!dev->bus->self) { | 440 | if (!dev->bus->self) { |
470 | DBG(" --> first child, no bridge. Allocating iommu table.\n"); | 441 | DBG(" --> first child, no bridge. Allocating iommu table.\n"); |
471 | tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | 442 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
443 | PCI_DN(dn)->phb->node); | ||
472 | iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); | 444 | iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); |
473 | PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); | 445 | PCI_DN(dn)->iommu_table = iommu_init_table(tbl, |
446 | PCI_DN(dn)->phb->node); | ||
474 | 447 | ||
475 | return; | 448 | return; |
476 | } | 449 | } |
@@ -516,7 +489,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) | |||
516 | { | 489 | { |
517 | struct device_node *pdn, *dn; | 490 | struct device_node *pdn, *dn; |
518 | struct iommu_table *tbl; | 491 | struct iommu_table *tbl; |
519 | int *dma_window = NULL; | 492 | unsigned char *dma_window = NULL; |
520 | struct pci_dn *pci; | 493 | struct pci_dn *pci; |
521 | 494 | ||
522 | DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev)); | 495 | DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev)); |
@@ -531,8 +504,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) | |||
531 | 504 | ||
532 | for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; | 505 | for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; |
533 | pdn = pdn->parent) { | 506 | pdn = pdn->parent) { |
534 | dma_window = (unsigned int *) | 507 | dma_window = get_property(pdn, "ibm,dma-window", NULL); |
535 | get_property(pdn, "ibm,dma-window", NULL); | ||
536 | if (dma_window) | 508 | if (dma_window) |
537 | break; | 509 | break; |
538 | } | 510 | } |
@@ -553,12 +525,12 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) | |||
553 | /* iommu_table_setparms_lpar needs bussubno. */ | 525 | /* iommu_table_setparms_lpar needs bussubno. */ |
554 | pci->bussubno = pci->phb->bus->number; | 526 | pci->bussubno = pci->phb->bus->number; |
555 | 527 | ||
556 | tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), | 528 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
557 | GFP_KERNEL); | 529 | pci->phb->node); |
558 | 530 | ||
559 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); | 531 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); |
560 | 532 | ||
561 | pci->iommu_table = iommu_init_table(tbl); | 533 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); |
562 | } | 534 | } |
563 | 535 | ||
564 | if (pdn != dn) | 536 | if (pdn != dn) |
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index e0000ce769e5..2e4e04042d85 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c | |||
@@ -348,7 +348,7 @@ static int enable_surveillance(int timeout) | |||
348 | return 0; | 348 | return 0; |
349 | 349 | ||
350 | if (error == -EINVAL) { | 350 | if (error == -EINVAL) { |
351 | printk(KERN_INFO "rtasd: surveillance not supported\n"); | 351 | printk(KERN_DEBUG "rtasd: surveillance not supported\n"); |
352 | return 0; | 352 | return 0; |
353 | } | 353 | } |
354 | 354 | ||
@@ -440,7 +440,7 @@ static int rtasd(void *unused) | |||
440 | goto error; | 440 | goto error; |
441 | } | 441 | } |
442 | 442 | ||
443 | printk(KERN_INFO "RTAS daemon started\n"); | 443 | printk(KERN_DEBUG "RTAS daemon started\n"); |
444 | 444 | ||
445 | DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); | 445 | DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); |
446 | 446 | ||
@@ -487,7 +487,7 @@ static int __init rtas_init(void) | |||
487 | 487 | ||
488 | /* No RTAS */ | 488 | /* No RTAS */ |
489 | if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { | 489 | if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { |
490 | printk(KERN_INFO "rtasd: no event-scan on system\n"); | 490 | printk(KERN_DEBUG "rtasd: no event-scan on system\n"); |
491 | return -ENODEV; | 491 | return -ENODEV; |
492 | } | 492 | } |
493 | 493 | ||
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 50643496eb63..77a5bb1d9c30 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c | |||
@@ -107,9 +107,9 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, | |||
107 | /* Break to sleep default time */ | 107 | /* Break to sleep default time */ |
108 | break; | 108 | break; |
109 | default: | 109 | default: |
110 | if (status > 9900 && status <= 9905) { | 110 | /* Assume extended busy */ |
111 | wait_time = rtas_extended_busy_delay_time(status); | 111 | wait_time = rtas_busy_delay_time(status); |
112 | } else { | 112 | if (!wait_time) { |
113 | printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); | 113 | printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); |
114 | return -EIO; | 114 | return -EIO; |
115 | } | 115 | } |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 3ba87835757e..1e28518c6121 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -235,14 +235,14 @@ static void __init pSeries_setup_arch(void) | |||
235 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { | 235 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
236 | vpa_init(boot_cpuid); | 236 | vpa_init(boot_cpuid); |
237 | if (get_lppaca()->shared_proc) { | 237 | if (get_lppaca()->shared_proc) { |
238 | printk(KERN_INFO "Using shared processor idle loop\n"); | 238 | printk(KERN_DEBUG "Using shared processor idle loop\n"); |
239 | ppc_md.power_save = pseries_shared_idle_sleep; | 239 | ppc_md.power_save = pseries_shared_idle_sleep; |
240 | } else { | 240 | } else { |
241 | printk(KERN_INFO "Using dedicated idle loop\n"); | 241 | printk(KERN_DEBUG "Using dedicated idle loop\n"); |
242 | ppc_md.power_save = pseries_dedicated_idle_sleep; | 242 | ppc_md.power_save = pseries_dedicated_idle_sleep; |
243 | } | 243 | } |
244 | } else { | 244 | } else { |
245 | printk(KERN_INFO "Using default idle loop\n"); | 245 | printk(KERN_DEBUG "Using default idle loop\n"); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 248 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c deleted file mode 100644 index 8e53e04ada8b..000000000000 --- a/arch/powerpc/platforms/pseries/vio.c +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
1 | /* | ||
2 | * IBM PowerPC pSeries Virtual I/O Infrastructure Support. | ||
3 | * | ||
4 | * Copyright (c) 2003-2005 IBM Corp. | ||
5 | * Dave Engebretsen engebret@us.ibm.com | ||
6 | * Santiago Leon santil@us.ibm.com | ||
7 | * Hollis Blanchard <hollisb@us.ibm.com> | ||
8 | * Stephen Rothwell | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/kobject.h> | ||
20 | #include <asm/iommu.h> | ||
21 | #include <asm/dma.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/vio.h> | ||
24 | #include <asm/hvcall.h> | ||
25 | #include <asm/tce.h> | ||
26 | |||
27 | extern struct subsystem devices_subsys; /* needed for vio_find_name() */ | ||
28 | |||
29 | static void probe_bus_pseries(void) | ||
30 | { | ||
31 | struct device_node *node_vroot, *of_node; | ||
32 | |||
33 | node_vroot = find_devices("vdevice"); | ||
34 | if ((node_vroot == NULL) || (node_vroot->child == NULL)) | ||
35 | /* this machine doesn't do virtual IO, and that's ok */ | ||
36 | return; | ||
37 | |||
38 | /* | ||
39 | * Create struct vio_devices for each virtual device in the device tree. | ||
40 | * Drivers will associate with them later. | ||
41 | */ | ||
42 | for (of_node = node_vroot->child; of_node != NULL; | ||
43 | of_node = of_node->sibling) { | ||
44 | printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); | ||
45 | vio_register_device_node(of_node); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * vio_match_device_pseries: - Tell if a pSeries VIO device matches a | ||
51 | * vio_device_id | ||
52 | */ | ||
53 | static int vio_match_device_pseries(const struct vio_device_id *id, | ||
54 | const struct vio_dev *dev) | ||
55 | { | ||
56 | return (strncmp(dev->type, id->type, strlen(id->type)) == 0) && | ||
57 | device_is_compatible(dev->dev.platform_data, id->compat); | ||
58 | } | ||
59 | |||
60 | static void vio_release_device_pseries(struct device *dev) | ||
61 | { | ||
62 | /* XXX free TCE table */ | ||
63 | of_node_put(dev->platform_data); | ||
64 | } | ||
65 | |||
66 | static ssize_t viodev_show_devspec(struct device *dev, | ||
67 | struct device_attribute *attr, char *buf) | ||
68 | { | ||
69 | struct device_node *of_node = dev->platform_data; | ||
70 | |||
71 | return sprintf(buf, "%s\n", of_node->full_name); | ||
72 | } | ||
73 | DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); | ||
74 | |||
75 | static void vio_unregister_device_pseries(struct vio_dev *viodev) | ||
76 | { | ||
77 | device_remove_file(&viodev->dev, &dev_attr_devspec); | ||
78 | } | ||
79 | |||
80 | static struct vio_bus_ops vio_bus_ops_pseries = { | ||
81 | .match = vio_match_device_pseries, | ||
82 | .unregister_device = vio_unregister_device_pseries, | ||
83 | .release_device = vio_release_device_pseries, | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus | ||
88 | */ | ||
89 | static int __init vio_bus_init_pseries(void) | ||
90 | { | ||
91 | int err; | ||
92 | |||
93 | err = vio_bus_init(&vio_bus_ops_pseries); | ||
94 | if (err == 0) | ||
95 | probe_bus_pseries(); | ||
96 | return err; | ||
97 | } | ||
98 | |||
99 | __initcall(vio_bus_init_pseries); | ||
100 | |||
101 | /** | ||
102 | * vio_build_iommu_table: - gets the dma information from OF and | ||
103 | * builds the TCE tree. | ||
104 | * @dev: the virtual device. | ||
105 | * | ||
106 | * Returns a pointer to the built tce tree, or NULL if it can't | ||
107 | * find property. | ||
108 | */ | ||
109 | static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | ||
110 | { | ||
111 | unsigned int *dma_window; | ||
112 | struct iommu_table *newTceTable; | ||
113 | unsigned long offset; | ||
114 | int dma_window_property_size; | ||
115 | |||
116 | dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); | ||
117 | if(!dma_window) { | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | ||
122 | |||
123 | /* There should be some code to extract the phys-encoded offset | ||
124 | using prom_n_addr_cells(). However, according to a comment | ||
125 | on earlier versions, it's always zero, so we don't bother */ | ||
126 | offset = dma_window[1] >> PAGE_SHIFT; | ||
127 | |||
128 | /* TCE table size - measured in tce entries */ | ||
129 | newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; | ||
130 | /* offset for VIO should always be 0 */ | ||
131 | newTceTable->it_offset = offset; | ||
132 | newTceTable->it_busno = 0; | ||
133 | newTceTable->it_index = (unsigned long)dma_window[0]; | ||
134 | newTceTable->it_type = TCE_VB; | ||
135 | |||
136 | return iommu_init_table(newTceTable); | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * vio_register_device_node: - Register a new vio device. | ||
141 | * @of_node: The OF node for this device. | ||
142 | * | ||
143 | * Creates and initializes a vio_dev structure from the data in | ||
144 | * of_node (dev.platform_data) and adds it to the list of virtual devices. | ||
145 | * Returns a pointer to the created vio_dev or NULL if node has | ||
146 | * NULL device_type or compatible fields. | ||
147 | */ | ||
148 | struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | ||
149 | { | ||
150 | struct vio_dev *viodev; | ||
151 | unsigned int *unit_address; | ||
152 | unsigned int *irq_p; | ||
153 | |||
154 | /* we need the 'device_type' property, in order to match with drivers */ | ||
155 | if ((NULL == of_node->type)) { | ||
156 | printk(KERN_WARNING | ||
157 | "%s: node %s missing 'device_type'\n", __FUNCTION__, | ||
158 | of_node->name ? of_node->name : "<unknown>"); | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | unit_address = (unsigned int *)get_property(of_node, "reg", NULL); | ||
163 | if (!unit_address) { | ||
164 | printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, | ||
165 | of_node->name ? of_node->name : "<unknown>"); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | /* allocate a vio_dev for this node */ | ||
170 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
171 | if (!viodev) { | ||
172 | return NULL; | ||
173 | } | ||
174 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
175 | |||
176 | viodev->dev.platform_data = of_node_get(of_node); | ||
177 | |||
178 | viodev->irq = NO_IRQ; | ||
179 | irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); | ||
180 | if (irq_p) { | ||
181 | int virq = virt_irq_create_mapping(*irq_p); | ||
182 | if (virq == NO_IRQ) { | ||
183 | printk(KERN_ERR "Unable to allocate interrupt " | ||
184 | "number for %s\n", of_node->full_name); | ||
185 | } else | ||
186 | viodev->irq = irq_offset_up(virq); | ||
187 | } | ||
188 | |||
189 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); | ||
190 | viodev->name = of_node->name; | ||
191 | viodev->type = of_node->type; | ||
192 | viodev->unit_address = *unit_address; | ||
193 | viodev->iommu_table = vio_build_iommu_table(viodev); | ||
194 | |||
195 | /* register with generic device framework */ | ||
196 | if (vio_register_device(viodev) == NULL) { | ||
197 | /* XXX free TCE table */ | ||
198 | kfree(viodev); | ||
199 | return NULL; | ||
200 | } | ||
201 | device_create_file(&viodev->dev, &dev_attr_devspec); | ||
202 | |||
203 | return viodev; | ||
204 | } | ||
205 | EXPORT_SYMBOL(vio_register_device_node); | ||
206 | |||
207 | /** | ||
208 | * vio_get_attribute: - get attribute for virtual device | ||
209 | * @vdev: The vio device to get property. | ||
210 | * @which: The property/attribute to be extracted. | ||
211 | * @length: Pointer to length of returned data size (unused if NULL). | ||
212 | * | ||
213 | * Calls prom.c's get_property() to return the value of the | ||
214 | * attribute specified by the preprocessor constant @which | ||
215 | */ | ||
216 | const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) | ||
217 | { | ||
218 | return get_property(vdev->dev.platform_data, (char*)which, length); | ||
219 | } | ||
220 | EXPORT_SYMBOL(vio_get_attribute); | ||
221 | |||
222 | /* vio_find_name() - internal because only vio.c knows how we formatted the | ||
223 | * kobject name | ||
224 | * XXX once vio_bus_type.devices is actually used as a kset in | ||
225 | * drivers/base/bus.c, this function should be removed in favor of | ||
226 | * "device_find(kobj_name, &vio_bus_type)" | ||
227 | */ | ||
228 | static struct vio_dev *vio_find_name(const char *kobj_name) | ||
229 | { | ||
230 | struct kobject *found; | ||
231 | |||
232 | found = kset_find_obj(&devices_subsys.kset, kobj_name); | ||
233 | if (!found) | ||
234 | return NULL; | ||
235 | |||
236 | return to_vio_dev(container_of(found, struct device, kobj)); | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * vio_find_node - find an already-registered vio_dev | ||
241 | * @vnode: device_node of the virtual device we're looking for | ||
242 | */ | ||
243 | struct vio_dev *vio_find_node(struct device_node *vnode) | ||
244 | { | ||
245 | uint32_t *unit_address; | ||
246 | char kobj_name[BUS_ID_SIZE]; | ||
247 | |||
248 | /* construct the kobject name from the device node */ | ||
249 | unit_address = (uint32_t *)get_property(vnode, "reg", NULL); | ||
250 | if (!unit_address) | ||
251 | return NULL; | ||
252 | snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); | ||
253 | |||
254 | return vio_find_name(kobj_name); | ||
255 | } | ||
256 | EXPORT_SYMBOL(vio_find_node); | ||
257 | |||
258 | int vio_enable_interrupts(struct vio_dev *dev) | ||
259 | { | ||
260 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); | ||
261 | if (rc != H_SUCCESS) | ||
262 | printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); | ||
263 | return rc; | ||
264 | } | ||
265 | EXPORT_SYMBOL(vio_enable_interrupts); | ||
266 | |||
267 | int vio_disable_interrupts(struct vio_dev *dev) | ||
268 | { | ||
269 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); | ||
270 | if (rc != H_SUCCESS) | ||
271 | printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); | ||
272 | return rc; | ||
273 | } | ||
274 | EXPORT_SYMBOL(vio_disable_interrupts); | ||
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 2d60ea30fed6..b14f9b5c114e 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -522,7 +522,7 @@ nextnode: | |||
522 | 522 | ||
523 | np = of_find_node_by_type(NULL, "interrupt-controller"); | 523 | np = of_find_node_by_type(NULL, "interrupt-controller"); |
524 | if (!np) { | 524 | if (!np) { |
525 | printk(KERN_WARNING "xics: no ISA interrupt controller\n"); | 525 | printk(KERN_DEBUG "xics: no ISA interrupt controller\n"); |
526 | xics_irq_8259_cascade_real = -1; | 526 | xics_irq_8259_cascade_real = -1; |
527 | xics_irq_8259_cascade = -1; | 527 | xics_irq_8259_cascade = -1; |
528 | } else { | 528 | } else { |
@@ -641,23 +641,26 @@ void xics_teardown_cpu(int secondary) | |||
641 | ops->cppr_info(cpu, 0x00); | 641 | ops->cppr_info(cpu, 0x00); |
642 | iosync(); | 642 | iosync(); |
643 | 643 | ||
644 | /* Clear IPI */ | ||
645 | ops->qirr_info(cpu, 0xff); | ||
646 | |||
647 | /* | ||
648 | * we need to EOI the IPI if we got here from kexec down IPI | ||
649 | * | ||
650 | * probably need to check all the other interrupts too | ||
651 | * should we be flagging idle loop instead? | ||
652 | * or creating some task to be scheduled? | ||
653 | */ | ||
654 | ops->xirr_info_set(cpu, XICS_IPI); | ||
655 | |||
644 | /* | 656 | /* |
645 | * Some machines need to have at least one cpu in the GIQ, | 657 | * Some machines need to have at least one cpu in the GIQ, |
646 | * so leave the master cpu in the group. | 658 | * so leave the master cpu in the group. |
647 | */ | 659 | */ |
648 | if (secondary) { | 660 | if (secondary) |
649 | /* | ||
650 | * we need to EOI the IPI if we got here from kexec down IPI | ||
651 | * | ||
652 | * probably need to check all the other interrupts too | ||
653 | * should we be flagging idle loop instead? | ||
654 | * or creating some task to be scheduled? | ||
655 | */ | ||
656 | ops->xirr_info_set(cpu, XICS_IPI); | ||
657 | rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, | 661 | rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, |
658 | (1UL << interrupt_server_size) - 1 - | 662 | (1UL << interrupt_server_size) - 1 - |
659 | default_distrib_server, 0); | 663 | default_distrib_server, 0); |
660 | } | ||
661 | } | 664 | } |
662 | 665 | ||
663 | #ifdef CONFIG_HOTPLUG_CPU | 666 | #ifdef CONFIG_HOTPLUG_CPU |