From moilanen at austin.ibm.com Wed Jun 1 01:12:25 2005 From: moilanen at austin.ibm.com (Jake Moilanen) Date: Tue, 31 May 2005 10:12:25 -0500 Subject: [PATCH] PCI device-node failure detection Message-ID: <20050531101225.510efbf7.moilanen@austin.ibm.com> OpenFirmware marks devices as failed in the device-tree when a hardware problem is detected. The kernel needs to fail config reads/writes to prevent a kernel crash when incorrect data is read. This patch validates that the device-node is not marked "fail" when config space reads/writes are attempted. Signed-off-by: Jake Moilanen Index: 2.6.12/arch/ppc64/kernel/prom.c =================================================================== --- 2.6.12.orig/arch/ppc64/kernel/prom.c 2005-03-02 01:38:13.000000000 -0600 +++ 2.6.12/arch/ppc64/kernel/prom.c 2005-05-27 18:44:33.172559207 -0500 @@ -1887,6 +1887,19 @@ *next = prop; } +int +dn_failed(struct device_node * dn) +{ + char * status; + + status = get_property(dn, "status", NULL); + + if (status && !strcmp(status, "fail")) + return 1; + + return 0; +} + #if 0 void print_properties(struct device_node *np) Index: 2.6.12/arch/ppc64/kernel/pSeries_pci.c =================================================================== --- 2.6.12.orig/arch/ppc64/kernel/pSeries_pci.c 2005-03-02 01:38:34.000000000 -0600 +++ 2.6.12/arch/ppc64/kernel/pSeries_pci.c 2005-05-27 18:44:33.183563164 -0500 @@ -96,7 +96,7 @@ /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn) + if (dn->devfn == devfn && !dn_failed(dn)) return rtas_read_config(dn, where, size, val); return PCIBIOS_DEVICE_NOT_FOUND; } @@ -138,7 +138,7 @@ /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn) + if (dn->devfn == devfn && !dn_failed(dn)) return rtas_write_config(dn, where, size, val); return PCIBIOS_DEVICE_NOT_FOUND; } Index: 2.6.12/include/asm-ppc64/prom.h =================================================================== --- 2.6.12.orig/include/asm-ppc64/prom.h 2005-03-02 01:38:33.000000000 -0600 +++ 2.6.12/include/asm-ppc64/prom.h 2005-05-27 18:44:33.192566401 -0500 @@ -225,5 +225,6 @@ extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); extern void prom_add_property(struct device_node* np, struct property* prop); +extern int dn_failed(struct device_node * dn); #endif /* _PPC64_PROM_H */ From linas at austin.ibm.com Wed Jun 1 02:06:28 2005 From: linas at austin.ibm.com (Linas Vepstas) Date: Tue, 31 May 2005 11:06:28 -0500 Subject: panic reboot stuck in rtas_os_term In-Reply-To: <20050525134617.24a2c940.moilanen@austin.ibm.com> References: <20050508083331.GA30329@suse.de> <20050508091533.GA30450@suse.de> <20050525065410.GA9430@suse.de> <20050525125352.2d08dc52.moilanen@austin.ibm.com> <20050525182413.GA18053@suse.de> <20050525134617.24a2c940.moilanen@austin.ibm.com> Message-ID: <20050531160628.GC31199@austin.ibm.com> On Wed, May 25, 2005 at 01:46:17PM -0500, Jake Moilanen was heard to remark: > > > > But the rtas call does not return, so the kernel cant do anything. > > There was a firmware problem w/ os-term awhile ago (returned hardware > error). It may be related. How old is your firmware? Is this GA level firmware? If some customer out in the field has GA level h/w running SLES9 successfully today, will upgrading to SP1 (or SP2) "break" the h/w? (i.e. force the customer to upgrade firmware?) I'm wondering if that's why Olaf is complaining. Should we have some RAS daemon that nags the user: "this kernel version requires at least firmware level XXX to operate properly"? --linas From nathanl at austin.ibm.com Wed Jun 1 02:12:40 2005 From: nathanl at austin.ibm.com (Nathan Lynch) Date: Tue, 31 May 2005 11:12:40 -0500 Subject: [PATCH] ppc64: set/clear SMT capable bit at boot In-Reply-To: <20050529234154.GG11066@krispykreme> References: <20050529234154.GG11066@krispykreme> Message-ID: <1117555960.10583.6.camel@pants.austin.ibm.com> On Mon, 2005-05-30 at 09:41 +1000, Anton Blanchard wrote: > Paul/Nathan, does this look OK to you? Looks fine to me. Nathan From olh at suse.de Wed Jun 1 04:38:41 2005 From: olh at suse.de (Olaf Hering) Date: Tue, 31 May 2005 20:38:41 +0200 Subject: panic reboot stuck in rtas_os_term In-Reply-To: <20050531160628.GC31199@austin.ibm.com> References: <20050508083331.GA30329@suse.de> <20050508091533.GA30450@suse.de> <20050525065410.GA9430@suse.de> <20050525125352.2d08dc52.moilanen@austin.ibm.com> <20050525182413.GA18053@suse.de> <20050525134617.24a2c940.moilanen@austin.ibm.com> <20050531160628.GC31199@austin.ibm.com> Message-ID: <20050531183841.GA13988@suse.de> On Tue, May 31, Linas Vepstas wrote: > I'm wondering if that's why Olaf is complaining. No, I just expected a reboot on panic, like in the good old days. But even a p640 just activates the service processor, instead of rebooting. SLES8 kernels do not have the "ibm,os-term" call, they are new in 2.6. The current way is ok, one just has to know how to deal with it. From ntl at pobox.com Wed Jun 1 05:51:27 2005 From: ntl at pobox.com (Nathan Lynch) Date: Tue, 31 May 2005 14:51:27 -0500 Subject: [PATCH] PCI device-node failure detection In-Reply-To: <20050531101225.510efbf7.moilanen@austin.ibm.com> References: <20050531101225.510efbf7.moilanen@austin.ibm.com> Message-ID: <20050531195127.GD3723@otto> Jake Moilanen wrote: > OpenFirmware marks devices as failed in the device-tree when a hardware > problem is detected. The kernel needs to fail config reads/writes to > prevent a kernel crash when incorrect data is read. > > This patch validates that the device-node is not marked "fail" when > config space reads/writes are attempted. > > Signed-off-by: Jake Moilanen > > Index: 2.6.12/arch/ppc64/kernel/prom.c > =================================================================== > --- 2.6.12.orig/arch/ppc64/kernel/prom.c 2005-03-02 01:38:13.000000000 -0600 > +++ 2.6.12/arch/ppc64/kernel/prom.c 2005-05-27 18:44:33.172559207 -0500 > @@ -1887,6 +1887,19 @@ > *next = prop; > } > > +int > +dn_failed(struct device_node * dn) > +{ > + char * status; > + > + status = get_property(dn, "status", NULL); > + > + if (status && !strcmp(status, "fail")) > + return 1; > + > + return 0; > +} > + "fail" is not the only possible state that would indicate that the device is unusable, if I'm reading IEEE 1275 right. There is also "disabled" and "fail-xxx" where xxx is additional info about the fault. I've never seen "fail-xxx" myself but I've seen "disabled" on devices that were deconfigured by firmware (failing cpu iirc). Unless we want to treat "disabled" and "fail[-xxx]" differently, I think we should be checking that the status property, if present, says "okay". Something like: int dn_failed(struct device_node *dn) { char *status = get_property(dn, "status", NULL); if (!status) return 0; if (!strcmp(status, "okay")) return 0; return 1; } Also, I think this function could be made a static helper in pSeries_pci.c until something outside of that file needs it. Nathan From olh at suse.de Wed Jun 1 06:29:31 2005 From: olh at suse.de (Olaf Hering) Date: Tue, 31 May 2005 22:29:31 +0200 Subject: [PATCH] allow xmon=bt to print a backtrace by default Message-ID: <20050531202931.GA14769@suse.de> xmon does not print a backtrace per default. This is bad on systems with USB keyboard, the most needed info about the crash is lost. Booting with xmon=bt enables the autobacktrace functionality. Signed-off-by: Olaf Hering Index: linux-2.6.11/arch/ppc64/kernel/setup.c =================================================================== --- linux-2.6.11.orig/arch/ppc64/kernel/setup.c +++ linux-2.6.11/arch/ppc64/kernel/setup.c @@ -633,7 +633,7 @@ void __init setup_system(void) * Initialize xmon */ #ifdef CONFIG_XMON_DEFAULT - xmon_init(); + xmon_init(0); #endif /* * Register early console @@ -1345,12 +1345,14 @@ static int __init early_xmon(char *p) { /* ensure xmon is enabled */ if (p) { + if (strncmp(p, "bt", 2) == 0) + xmon_init(1); if (strncmp(p, "on", 2) == 0) - xmon_init(); + xmon_init(0); if (strncmp(p, "early", 5) != 0) return 0; } - xmon_init(); + xmon_init(0); debugger(NULL); return 0; Index: linux-2.6.11/arch/ppc64/xmon/start.c =================================================================== --- linux-2.6.11.orig/arch/ppc64/xmon/start.c +++ linux-2.6.11/arch/ppc64/xmon/start.c @@ -27,7 +27,7 @@ static void sysrq_handle_xmon(int key, s struct tty_struct *tty) { /* ensure xmon is enabled */ - xmon_init(); + xmon_init(0); debugger(pt_regs); } Index: linux-2.6.11/arch/ppc64/xmon/xmon.c =================================================================== --- linux-2.6.11.orig/arch/ppc64/xmon/xmon.c +++ linux-2.6.11/arch/ppc64/xmon/xmon.c @@ -47,6 +47,7 @@ static int xmon_gate; #endif /* CONFIG_SMP */ static unsigned long in_xmon = 0; +static unsigned long xmon_auto_backtrace; static unsigned long adrs; static int size = 1; @@ -131,6 +132,8 @@ static void csum(void); static void bootcmds(void); void dump_segments(void); static void symbol_lookup(void); +static void xmon_show_stack(unsigned long sp, unsigned long lr, + unsigned long pc); static void xmon_print_symbol(unsigned long address, const char *mid, const char *after); static const char *getvecname(unsigned long vec); @@ -767,6 +770,9 @@ cmds(struct pt_regs *excp) last_cmd = NULL; xmon_regs = excp; + if (xmon_auto_backtrace) + xmon_show_stack(excp->gpr[1], excp->link, excp->nip); + for(;;) { #ifdef CONFIG_SMP printf("%x:", smp_processor_id()); @@ -2485,8 +2491,10 @@ static void dump_stab(void) } } -void xmon_init(void) +void xmon_init(int bt) { + if (bt) + xmon_auto_backtrace = 1; __debugger = xmon; __debugger_ipi = xmon_ipi; __debugger_bpt = xmon_bpt; Index: linux-2.6.11/include/asm-ppc64/system.h =================================================================== --- linux-2.6.11.orig/include/asm-ppc64/system.h +++ linux-2.6.11/include/asm-ppc64/system.h @@ -88,7 +88,7 @@ DEBUGGER_BOILERPLATE(debugger_dabr_match DEBUGGER_BOILERPLATE(debugger_fault_handler) #ifdef CONFIG_XMON -extern void xmon_init(void); +extern void xmon_init(int bt); #endif #else From linas at austin.ibm.com Wed Jun 1 06:30:28 2005 From: linas at austin.ibm.com (Linas Vepstas) Date: Tue, 31 May 2005 15:30:28 -0500 Subject: [PATCH]: PCI Error Recovery Implementation Message-ID: <20050531203028.GD31199@austin.ibm.com> Hi, Attached is the latest and greatest greatest PCI error recovery patch. Its posted here as one giant patch, but logically consists of a number of different pieces: 1) generic modifications to include/linux/pci.h, as per emails in last round of discussion. 2) Documentation/pci-error-recovery.txt describing the API. This is a cut-n-paste-modified copy of BenH's email. I changed the names of a few routines, and added notes about the current ppc64 implementation. 3) working patches to the SCSI ipr and symbios device drivers to use this API to recover from PCI errors. These actually work. I plan to have a patch for e1000 "real soon now"(TM). 4) ppc64-specific patches that use the API to notify the device of PCI errors. Please review. I want to get this submitted into mainline ASAP. --linas Signed-off-by: Linas Vepstas -------------- next part -------------- --- include/linux/pci.h.linas-orig 2005-04-29 20:27:22.000000000 -0500 +++ include/linux/pci.h 2005-05-31 13:47:46.000000000 -0500 @@ -659,6 +659,81 @@ struct pci_dynids { unsigned int use_driver_data:1; /* pci_driver->driver_data is used */ }; +/* ---------------------------------------------------------------- */ +/** PCI error recovery infrastructure. If a PCI device driver provides + * a set fof callbacks in struct pci_error_handlers, then that device driver + * will be notified of PCI bus errors, and can be driven to recovery. + */ + +enum pci_channel_state { + pci_channel_io_normal = 0, /* I/O channel is in normal state */ + pci_channel_io_frozen = 1, /* I/O to channel is blocked */ + pci_channel_io_perm_failure, /* pci card is dead */ +}; + +enum pcierr_result { + PCIERR_RESULT_NONE=0, /* no result/none/not supported in device driver */ + PCIERR_RESULT_CAN_RECOVER=1, /* Device driver can recover without slot reset */ + PCIERR_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */ + PCIERR_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */ + PCIERR_RESULT_RECOVERED, /* Device driver is fully recovered and operational */ +}; + +/* PCI bus error event callbacks */ +struct pci_error_handlers +{ + int (*error_detected)(struct pci_dev *dev, enum pci_channel_state error); + int (*mmio_enabled)(struct pci_dev *dev); /* MMIO has been reanbled, but not DMA */ + int (*link_reset)(struct pci_dev *dev); /* PCI Express link has been reset */ + int (*slot_reset)(struct pci_dev *dev); /* PCI slot has been reset */ + void (*resume)(struct pci_dev *dev); /* Device driver may resume normal operations */ +}; + +/** + * PCI Error notifier event flags. + */ +#define PEH_NOTIFY_ERROR 1 + +/** PEH event -- structure holding pci controller data that describes + * a change in the isolation status of a PCI slot. A pointer + * to this struct is passed as the data pointer in a notify callback. + */ +struct peh_event { + struct list_head list; + struct pci_dev *dev; /* affected device */ + enum pci_channel_state state; /* PCI bus state for the affected device */ + int time_unavail; /* milliseconds until device might be available */ +}; + +/** + * peh_send_failure_event - generate a PCI error event + * @dev pci device + * + * This routine builds a PCI error event which will be delivered + * to all listeners on the peh_notifier_chain. + * + * This routine can be called within an interrupt context; + * the actual event will be delivered in a normal context + * (from a workqueue). + */ +int peh_send_failure_event (struct pci_dev *dev, + enum pci_channel_state state, + int time_unavail); + +/** + * peh_register_notifier - Register to find out about EEH events. + * @nb: notifier block to callback on events + */ +int peh_register_notifier(struct notifier_block *nb); + +/** + * peh_unregister_notifier - Unregister to an EEH event notifier. + * @nb: notifier block to callback on events + */ +int peh_unregister_notifier(struct notifier_block *nb); + +/* ---------------------------------------------------------------- */ + struct module; struct pci_driver { struct list_head node; @@ -671,6 +746,7 @@ struct pci_driver { int (*resume) (struct pci_dev *dev); /* Device woken up */ int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ + struct pci_error_handlers err_handler; struct device_driver driver; struct pci_dynids dynids; }; --- Documentation/pci-error-recovery.txt.linas-orig 2005-05-06 17:44:41.000000000 -0500 +++ Documentation/pci-error-recovery.txt 2005-05-31 15:08:56.000000000 -0500 @@ -0,0 +1,232 @@ + + PCI Error Recovery + ------------------ + May 31, 2005 + + +Some PCI bus controllers are able to detect certain "hard" PCI errors +on the bus, such as parity errors on the data and address busses, as +well as SERR and PERR errors. These chipsets are then able to disable +I/O to/from the affected device, so that, for example, a bad DMA +address doesn't end up corrupting system memory. These same chipsets +are also able to reset the affected PCI device, and return it to +working condition. This document describes a generic API form +performing error recovery. + +The core idea is that after a PCI error has been detected, there must +be a way for the kernel to coordinate with all affected device drivers +so that the pci card can be made operational again, possibly after +performing a full electrical #RST of the PCI card. The API below +provides a generic API for device drivers to be notified of PCI +errors, and to be notified of, and respond to, a reset sequence. + +Preliminary sketch of API, cut-n-pasted-n-modified email from +Ben Herrenschmidt, circa 5 april 2005 + +The error recovery API support is exposed to the driver in the form of +a structure of function pointers pointed to by a new field in struct +pci_driver. The absence of this pointer in pci_driver denotes an +"non-aware" driver, behaviour on these is platform dependant. +Platforms like ppc64 can try to simulate pci hotplug remove/add. + +The definition of "pci_error_token" is not covered here. It is based on +Seto's work on the synchronous error detection. We still need to define +functions for extracting infos out of an opaque error token. This is +separate from this API. + +This structure has the form: + +struct pci_error_handlers +{ + int (*error_detected)(struct pci_dev *dev, pci_error_token error); + int (*mmio_enabled)(struct pci_dev *dev); + int (*resume)(struct pci_dev *dev); + int (*link_reset)(struct pci_dev *dev); + int (*slot_reset)(struct pci_dev *dev); +}; + +A driver doesn't have to implement all of these callbacks. The +only mandatory one is error_detected(). If a callback is not +implemented, the corresponding feature is considered unsupported. +For example, if mmio_enabled() and resume() aren't there, then the +driver is assumed as not doing any direct recovery and requires +a reset. If link_reset() is not implemented, the card is assumed as +not caring about link resets, in which case, if recover is supported, +the core can try recover (but not slot_reset() unless it really did +reset the slot). If slot_reset() is not supported, link_reset() can +be called instead on a slot reset. + +At first, the call will always be : + + 1) error_detected() + + Error detected. This is sent once after an error has been detected. At +this point, the device might not be accessible anymore depending on the +platform (the slot will be isolated on ppc64). The driver may already +have "noticed" the error because of a failing IO, but this is the proper +"synchronisation point", that is, it gives a chance to the driver to +cleanup, waiting for pending stuff (timers, whatever, etc...) to +complete; it can take semaphores, schedule, etc... everything but touch +the device. Within this function and after it returns, the driver +shouldn't do any new IOs. Called in task context. This is sort of a +"quiesce" point. See note about interrupts at the end of this doc. + + Result codes: + - PCIERR_RESULT_CAN_RECOVER: + Driever returns this if it thinks it might be able to recover + the HW by just banging IOs or if it wants to be given + a chance to extract some diagnostic informations (see + below). + - PCIERR_RESULT_NEED_RESET: + Driver returns this if it thinks it can't recover unless the + slot is reset. + - PCIERR_RESULT_DISCONNECT: + Return this if driver thinks it won't recover at all, + (this will detach the driver ? or just leave it + dangling ? to be decided) + +So at this point, we have called error_detected() for all drivers +on the segment that had the error. On ppc64, the slot is isolated. What +happens now typically depends on the result from the drivers. If all +drivers on the segment/slot return PCIERR_RESULT_CAN_RECOVER, we would +re-enable IOs on the slot (or do nothing special if the platform doesn't +isolate slots) and call 2). If not and we can reset slots, we go to 4), +if neither, we have a dead slot. If it's an hotplug slot, we might +"simulate" reset by triggering HW unplug/replug though. + +>>> Current ppc64 implementation assumes that a device driver will +>>> *not* schedule or semaphore in this routine; the current ppc64 +>>> implementation uses one kernel thread to notify all devices; +>>> thus, of one device sleeps/schedules, all devices are affected. +>>> Doing better requires complex multi-threaded logic in the error +>>> recovery implementation (e.g. waiting for all notification threads +>>> to "join" before proceeding with recovery.) This seems excessively +>>> complex and not worth implementing. + + 2) mmio_enabled() + + This is the "early recovery" call. IOs are allowed again, but DMA is +not (hrm... to be discussed, I prefer not), with some restrictions. This +is NOT a callback for the driver to start operations again, only to +peek/poke at the device, extract diagnostic information, if any, and +eventually do things like trigger a device local reset or some such, +but not restart operations. This is sent if all drivers on a segment +agree that they can try to recover and no automatic link reset was +performed by the HW. If the platform can't just re-enable IOs without +a slot reset or a link reset, it doesn't call this callback and goes +directly to 3) or 4). All IOs should be done _synchronously_ from +within this callback, errors triggered by them will be returned via +the normal pci_check_whatever() api, no new error_detected() callback +will be issued due to an error happening here. However, such an error +might cause IOs to be re-blocked for the whole segment, and thus +invalidate the recovery that other devices on the same segment might +have done, forcing the whole segment into one of the next states, +that is link reset or slot reset. + + Result codes: + - PCIERR_RESULT_RECOVERED + Driver returns this if it thinks the device is fully + functionnal and thinks it is ready to start + normal driver operations again. There is no + guarantee that the driver will actually be + allowed to proceed, as another driver on the + same segment might have failed and thus triggered a + slot reset on platforms that support it. + + - PCIERR_RESULT_NEED_RESET + Driver returns this if it thinks the device is not + recoverable in it's current state and it needs a slot + reset to proceed. + + - PCIERR_RESULT_DISCONNECT + Same as above. Total failure, no recovery even after + reset driver dead. (To be defined more precisely) + +>>> The current ppc64 implementation does not implement this callback. + + 3) link_reset() + + This is called after the link has been reset. This is typically +a PCI Express specific state at this point and is done whenever a +non-fatal error has been detected that can be "solved" by resetting +the link. This call informs the driver of the reset and the driver +should check if the device appears to be in working condition. +This function acts a bit like 2) mmio_enabled(), in that the driver +is not supposed to restart normal driver I/O operations right away. +Instead, it should just "probe" the device to check it's recoverability +status. If all is right, then the core will call resume() once all +drivers have ack'd link_reset(). + + Result codes: + (identical to mmio_enabled) + +>>> The current ppc64 implementation does not implement this callback. + + 4) slot_reset() + + This is called after the slot has been soft or hard reset by the +platform. A soft reset consists of asserting the adapter #RST line +and then restoring the PCI BARs and PCI configuration header. If the +platform supports PCI hotplug, then it might instead perform a hard +reset by toggling power on the slot off/on. This call gives drivers +the chance to re-initialize the hardware (re-download firmware, etc.), +but drivers shouldn't restart normal I/O processing operations at +this point. (See note about interrupts; interrupts aren't guaranteed +to be delivered until the resume() callback has been called). If all +device drivers report success on this callback, the patform will call +resume() to complete the error handling and let the driver restart +normal I/O processing. + +A driver can still return a critical failure for this function if +it can't get the device operational after reset. If the platform +previously tried a soft reset, it migh now try a hard reset (power +cycle) and then call slot_reset() again. It the device still can't +be recovered, there is nothing more that can be done; the platform +will typically report a "permanent failure" in such a case. The +device will be considered "dead" in this case. + + Result codes: + - PCIERR_RESULT_DISCONNECT + Same as above. + + 5) resume() + + This is called if all drivers on the segment have returned +PCIERR_RESULT_RECOVERED from one of the 3 prevous callbacks. +That basically tells the driver to restart activity, tht everything +is back and running. No result code is taken into account here. If +a new error happens, it will restart a new error handling process. + +That's it. I think this covers all the possibilities. The way those +callbacks are called is platform policy. A platform with no slot reset +capability for example may want to just "ignore" drivers that can't +recover (disconnect them) and try to let other cards on the same segment +recover. Keep in mind that in most real life cases, though, there will +be only one driver per segment. + +Now, there is a note about interrupts. If you get an interrupt and your +device is dead or has been isolated, there is a problem :) + +After much thinking, I decided to leave that to the platform. That is, +the recovery API only precies that: + + - There is no guarantee that interrupt delivery can proceed from any +device on the segment starting from the error detection and until the +restart callback is sent, at which point interrupts are expected to be +fully operational. + + - There is no guarantee that interrupt delivery is stopped, that is, ad +river that gets an interrupts after detecting an error, or that detects +and error within the interrupt handler such that it prevents proper +ack'ing of the interrupt (and thus removal of the source) should just +return IRQ_NOTHANDLED. It's up to the platform to deal with taht +condition, typically by masking the irq source during the duration of +the error handling. It is expected that the platform "knows" which +interrupts are routed to error-management capable slots and can deal +with temporarily disabling that irq number during error processing (this +isn't terribly complex). That means some IRQ latency for other devices +sharing the interrupt, but there is simply no other way. High end +platforms aren't supposed to share interrupts between many devices +anyway :) + + --- drivers/pci/Makefile.linas-orig 2005-04-29 20:31:33.000000000 -0500 +++ drivers/pci/Makefile 2005-05-06 12:28:43.000000000 -0500 @@ -3,7 +3,7 @@ # obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ - names.o pci-driver.o search.o pci-sysfs.o \ + names.o pci-driver.o pci-error.o search.o pci-sysfs.o \ rom.o obj-$(CONFIG_PROC_FS) += proc.o --- drivers/pci/pci-error.c.linas-orig 2005-05-06 17:44:47.000000000 -0500 +++ drivers/pci/pci-error.c 2005-05-31 13:49:34.000000000 -0500 @@ -0,0 +1,152 @@ +/* + * pci-error.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#undef DEBUG + +/** Overview: + * PEH, or "PCI Error Handling" is a PCI bridge technology for + * dealing with PCI bus errors that can't be dealt with within the + * usual PCI framework, except by check-stopping the CPU. Systems + * that are designed for high-availability/reliability cannot afford + * to crash due to a "mere" PCI error, thus the need for PEH. + * An PEH-capable bridge operates by converting a detected error + * into a "slot freeze", taking the PCI adapter off-line, making + * the slot behave, from the OS'es point of view, as if the slot + * were "empty": all reads return 0xff's and all writes are silently + * ignored. PEH slot isolation events can be triggered by parity + * errors on the address or data busses (e.g. during posted writes), + * which in turn might be caused by low voltage on the bus, dust, + * vibration, humidity, radioactivity or plain-old failed hardware. + * + * Note, however, that one of the leading causes of PEH slot + * freeze events are buggy device drivers, buggy device microcode, + * or buggy device hardware. This is because any attempt by the + * device to bus-master data to a memory address that is not + * assigned to the device will trigger a slot freeze. (The idea + * is to prevent devices-gone-wild from corrupting system memory). + * Buggy hardware/drivers will have a miserable time co-existing + * with PEH. + */ + +/* PEH event workqueue setup. */ +static spinlock_t peh_eventlist_lock = SPIN_LOCK_UNLOCKED; +LIST_HEAD(peh_eventlist); +static void peh_event_handler(void *); +DECLARE_WORK(peh_event_wq, peh_event_handler, NULL); + +static struct notifier_block *peh_notifier_chain; + +/** + * peh_event_handler - dispatch PEH events. The detection of a frozen + * slot can occur inside an interrupt, where it can be hard to do + * anything about it. The goal of this routine is to pull these + * detection events out of the context of the interrupt handler, and + * re-dispatch them for processing at a later time in a normal context. + * + * @dummy - unused + */ +static void peh_event_handler(void *dummy) +{ + unsigned long flags; + struct peh_event *event; + + while (1) { + spin_lock_irqsave(&peh_eventlist_lock, flags); + event = NULL; + if (!list_empty(&peh_eventlist)) { + event = list_entry(peh_eventlist.next, struct peh_event, list); + list_del(&event->list); + } + spin_unlock_irqrestore(&peh_eventlist_lock, flags); + if (event == NULL) + break; + + printk(KERN_INFO "PEH: Detected PCI bus error on device " + "%s %s\n", + pci_name(event->dev), pci_pretty_name(event->dev)); + + notifier_call_chain (&peh_notifier_chain, + PEH_NOTIFY_ERROR, event); + + pci_dev_put(event->dev); + kfree(event); + } +} + + +/** + * peh_send_failure_event - generate a PCI error event + * @dev pci device + * + * This routine builds a PCI error event which will be delivered + * to all listeners on the peh_notifier_chain. + * + * This routine can be called within an interrupt context; + * the actual event will be delivered in a normal context + * (from a workqueue). + */ +int peh_send_failure_event (struct pci_dev *dev, + enum pci_channel_state state, + int time_unavail) +{ + unsigned long flags; + struct peh_event *event; + + event = kmalloc(sizeof(*event), GFP_ATOMIC); + if (event == NULL) { + printk (KERN_ERR "PEH: out of memory, event not handled\n"); + return 1; + } + + event->dev = dev; + event->state = state; + event->time_unavail = time_unavail; + + /* We may or may not be called in an interrupt context */ + spin_lock_irqsave(&peh_eventlist_lock, flags); + list_add(&event->list, &peh_eventlist); + spin_unlock_irqrestore(&peh_eventlist_lock, flags); + + schedule_work(&peh_event_wq); + + return 0; +} + +/** + * peh_register_notifier - Register to find out about EEH events. + * @nb: notifier block to callback on events + */ +int peh_register_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&peh_notifier_chain, nb); +} + +/** + * peh_unregister_notifier - Unregister to an EEH event notifier. + * @nb: notifier block to callback on events + */ +int peh_unregister_notifier(struct notifier_block *nb) +{ + return notifier_chain_unregister(&peh_notifier_chain, nb); +} + +/********************** END OF FILE ******************************/ --- drivers/scsi/ipr.c.linas-orig 2005-04-29 20:33:36.000000000 -0500 +++ drivers/scsi/ipr.c 2005-05-31 15:12:08.000000000 -0500 @@ -5306,6 +5306,85 @@ static void ipr_initiate_ioa_reset(struc shutdown_type); } +#ifdef CONFIG_SCSI_IPR_EEH_RECOVERY + +/** If the PCI slot is frozen, hold off all i/o + * activity; then, as soon as the slot is available again, + * initiate an adapter reset. + */ +static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd) +{ + list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); + ipr_cmd->done = ipr_reset_ioa_job; + return IPR_RC_JOB_RETURN; +} + +/** ipr_eeh_frozen -- called when slot has experience PCI bus error. + * This routine is called to tell us that the PCI bus is down. + * Can't do anything here, except put the device driver into a + * holding pattern, waiting for the PCI bus to come back. + */ +static void ipr_eeh_frozen (struct pci_dev *pdev) +{ + unsigned long flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); +} + +/** ipr_eeh_slot_reset - called when pci slot has been reset. + * + * This routine is called by the pci error recovery recovery + * code after the PCI slot has been reset, just before we + * should resume normal operations. + */ +static int ipr_eeh_slot_reset (struct pci_dev *pdev) +{ + unsigned long flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, + IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + + return PCIERR_RESULT_RECOVERED; +} + +/** This routine is called when the PCI bus has permanently + * failed. This routine should purge all pending I/O and + * shut down the device driver (close and unload). + * XXX Needs to be implemented. + */ +static void ipr_eeh_perm_failure (struct pci_dev *pdev) +{ +#if 0 // XXXXXXXXXXXXXXXXXXXXXXX + ipr_cmd->job_step = ipr_reset_shutdown_ioa; + rc = IPR_RC_JOB_CONTINUE; +#endif +} + +static int ipr_eeh_error_detected (struct pci_dev *pdev, + enum pci_channel_state state) +{ + switch (state) { + case pci_channel_io_frozen: + ipr_eeh_frozen (pdev); + return PCIERR_RESULT_NEED_RESET; + + case pci_channel_io_perm_failure: + ipr_eeh_perm_failure (pdev); + return PCIERR_RESULT_DISCONNECT; + break; + default: + break; + } + return PCIERR_RESULT_NEED_RESET; +} +#endif + /** * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) * @ioa_cfg: ioa cfg struct @@ -6015,6 +6094,10 @@ static struct pci_driver ipr_driver = { .id_table = ipr_pci_table, .probe = ipr_probe, .remove = ipr_remove, + .err_handler = { + .error_detected = ipr_eeh_error_detected, + .slot_reset = ipr_eeh_slot_reset, + }, .driver = { .shutdown = ipr_shutdown, }, --- drivers/scsi/sym53c8xx_2/sym_glue.c.linas-orig 2005-04-29 20:33:12.000000000 -0500 +++ drivers/scsi/sym53c8xx_2/sym_glue.c 2005-05-31 13:52:55.000000000 -0500 @@ -770,6 +770,10 @@ static irqreturn_t sym53c8xx_intr(int ir struct sym_hcb *np = (struct sym_hcb *)dev_id; if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("["); +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY + if (np->s.io_state != pci_channel_io_normal) + return IRQ_HANDLED; +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ spin_lock_irqsave(np->s.host->host_lock, flags); sym_interrupt(np); @@ -844,6 +848,27 @@ static void sym_eh_done(struct scsi_cmnd */ static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY +static void sym_eeh_timeout(u_long p) +{ + struct sym_eh_wait *ep = (struct sym_eh_wait *) p; + if (!ep) + return; + complete(&ep->done); +} + +static void sym_eeh_done(struct sym_eh_wait *ep) +{ + if (!ep) + return; + ep->timed_out = 0; + if (!del_timer(&ep->timer)) + return; + + complete(&ep->done); +} +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ + /* * Generic method for our eh processing. * The 'op' argument tells what we have to do. @@ -893,6 +918,37 @@ prepare: /* Try to proceed the operation we have been asked for */ sts = -1; +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY + + /* We may be in an error condition because the PCI bus + * went down. In this case, we need to wait until the + * PCI bus is reset, the card is reset, and only then + * proceed with the scsi error recovery. We'll wait + * for 15 seconds for this to happen. + */ +#define WAIT_FOR_PCI_RECOVERY 15 + if (np->s.io_state != pci_channel_io_normal) { + struct sym_eh_wait eeh, *eep = &eeh; + np->s.io_reset_wait = eep; + init_completion(&eep->done); + init_timer(&eep->timer); + eep->to_do = SYM_EH_DO_WAIT; + eep->timer.expires = jiffies + (WAIT_FOR_PCI_RECOVERY*HZ); + eep->timer.function = sym_eeh_timeout; + eep->timer.data = (u_long)eep; + eep->timed_out = 1; /* Be pessimistic for once :) */ + add_timer(&eep->timer); + spin_unlock_irq(np->s.host->host_lock); + wait_for_completion(&eep->done); + spin_lock_irq(np->s.host->host_lock); + if (eep->timed_out) { + printk (KERN_ERR "%s: Timed out waiting for PCI reset\n", + sym_name(np)); + } + np->s.io_reset_wait = NULL; + } +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ + switch(op) { case SYM_EH_ABORT: sts = sym_abort_scsiio(np, cmd, 1); @@ -1625,6 +1681,8 @@ static struct Scsi_Host * __devinit sym_ if (!np) goto attach_failed; np->s.device = dev->pdev; + np->s.io_state = pci_channel_io_normal; + np->s.io_reset_wait = NULL; np->bus_dmat = dev->pdev; /* Result in 1 DMA pool per HBA */ host_data->ncb = np; np->s.host = instance; @@ -2048,6 +2106,59 @@ static int sym_detach(struct sym_hcb *np return 1; } +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY +/** sym2_io_error_detected() is called when PCI error is detected */ +int sym2_io_error_detected (struct pci_dev *pdev, enum pci_channel_state state) +{ + struct sym_hcb *np = pci_get_drvdata(pdev); + + np->s.io_state = state; + // XXX If slot is permanently frozen, then what? + // Should we scsi_remove_host() maybe ?? + + /* Request a slot slot reset. */ + return PCIERR_RESULT_NEED_RESET; +} + +/** sym2_io_slot_reset is called when the pci bus has been reset. + * Restart the card from scratch. */ +int sym2_io_slot_reset (struct pci_dev *pdev) +{ + struct sym_hcb *np = pci_get_drvdata(pdev); + + msleep (500); // pure paranoia -- wait for device to settle + printk (KERN_INFO "%s: recovering from a PCI slot reset\n", + sym_name(np)); + + if (pci_enable_device(pdev)) + printk (KERN_ERR "%s: device setup failed most egregiously\n", + sym_name(np)); + + pci_set_master(pdev); + + /* Perform host reset only on one instance of the card */ + if (0 == PCI_FUNC (pdev->devfn)) + sym_reset_scsi_bus(np, 0); + + return PCIERR_RESULT_RECOVERED; +} + +/** sym2_io_resume is called when the error recovery driver + * tells us that its OK to resume normal operation. + */ +void sym2_io_resume (struct pci_dev *pdev) +{ + struct sym_hcb *np = pci_get_drvdata(pdev); + + /* Perform device startup only once for this card. */ + if (0 == PCI_FUNC (pdev->devfn)) + sym_start_up (np, 1); + + np->s.io_state = pci_channel_io_normal; + sym_eeh_done (np->s.io_reset_wait); +} +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ + /* * Driver host template. */ @@ -2359,6 +2470,11 @@ static struct pci_driver sym2_driver = { .id_table = sym2_id_table, .probe = sym2_probe, .remove = __devexit_p(sym2_remove), + .err_handler = { + .error_detected = sym2_io_error_detected, + .slot_reset = sym2_io_slot_reset, + .resume = sym2_io_resume, + }, }; static int __init sym2_init(void) --- drivers/scsi/sym53c8xx_2/sym_glue.h.linas-orig 2005-04-29 20:32:45.000000000 -0500 +++ drivers/scsi/sym53c8xx_2/sym_glue.h 2005-05-06 16:29:39.000000000 -0500 @@ -358,6 +358,10 @@ struct sym_shcb { char chip_name[8]; struct pci_dev *device; + /* pci bus i/o state; waiter for clearing of i/o state */ + enum pci_channel_state io_state; + struct sym_eh_wait *io_reset_wait; + struct Scsi_Host *host; void __iomem * mmio_va; /* MMIO kernel virtual address */ --- drivers/scsi/sym53c8xx_2/sym_hipd.c.linas-orig 2005-04-29 20:22:45.000000000 -0500 +++ drivers/scsi/sym53c8xx_2/sym_hipd.c 2005-05-20 15:40:43.000000000 -0500 @@ -2836,6 +2836,7 @@ void sym_interrupt (struct sym_hcb *np) u_char istat, istatc; u_char dstat; u_short sist; + u_int icnt; /* * interrupt on the fly ? @@ -2877,6 +2878,7 @@ void sym_interrupt (struct sym_hcb *np) sist = 0; dstat = 0; istatc = istat; + icnt = 0; do { if (istatc & SIP) sist |= INW (nc_sist); @@ -2884,6 +2886,14 @@ void sym_interrupt (struct sym_hcb *np) dstat |= INB (nc_dstat); istatc = INB (nc_istat); istat |= istatc; +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY + /* Prevent deadlock waiting on a condition that may never clear. */ + icnt ++; + if (100 < icnt) { + if (eeh_slot_is_isolated(np->s.device)) + return; + } +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ } while (istatc & (SIP|DIP)); if (DEBUG_FLAGS & DEBUG_TINY) --- drivers/scsi/Kconfig.linas-orig 2005-04-29 20:31:30.000000000 -0500 +++ drivers/scsi/Kconfig 2005-05-24 11:17:40.000000000 -0500 @@ -1032,6 +1032,14 @@ config SCSI_SYM53C8XX_IOMAPPED the card. This is significantly slower then using memory mapped IO. Most people should answer N. +config SCSI_SYM53C8XX_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on SCSI_SYM53C8XX_2 && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config SCSI_IPR tristate "IBM Power Linux RAID adapter support" depends on PCI && SCSI @@ -1057,6 +1065,14 @@ config SCSI_IPR_DUMP If you enable this support, the iprdump daemon can be used to capture adapter failure analysis information. +config SCSI_IPR_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on SCSI_IPR && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config SCSI_ZALON tristate "Zalon SCSI support" depends on GSC && SCSI --- arch/ppc64/defconfig.linas-orig 2005-05-20 12:16:19.000000000 -0500 +++ arch/ppc64/defconfig 2005-05-20 12:16:58.000000000 -0500 @@ -255,6 +255,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MOD CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set --- arch/ppc64/configs/pSeries_defconfig.linas-orig 2005-04-29 20:34:04.000000000 -0500 +++ arch/ppc64/configs/pSeries_defconfig 2005-05-24 11:18:45.000000000 -0500 @@ -275,9 +275,11 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MOD CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y CONFIG_SCSI_IPR=y # CONFIG_SCSI_IPR_TRACE is not set # CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_IPR_EEH_RECOVERY=y # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set --- include/asm-ppc64/eeh.h.linas-orig 2005-04-29 20:34:03.000000000 -0500 +++ include/asm-ppc64/eeh.h 2005-05-31 13:55:18.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* * eeh.h * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. * @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -23,6 +23,7 @@ #include #include #include +#include #include struct pci_dev; @@ -36,6 +37,11 @@ struct notifier_block; #define EEH_MODE_SUPPORTED (1<<0) #define EEH_MODE_NOCHECK (1<<1) #define EEH_MODE_ISOLATED (1<<2) +#define EEH_MODE_RECOVERING (1<<3) + +/* Max number of EEH freezes allowed before we consider the device + * to be permanently disabled. */ +#define EEH_MAX_ALLOWED_FREEZES 5 void __init eeh_init(void); unsigned long eeh_check_failure(const volatile void __iomem *token, @@ -59,35 +65,82 @@ void eeh_add_device_late(struct pci_dev * eeh_remove_device - undo EEH setup for the indicated pci device * @dev: pci device to be removed * - * This routine should be when a device is removed from a running - * system (e.g. by hotplug or dlpar). + * This routine should be called when a device is removed from + * a running system (e.g. by hotplug or dlpar). It unregisters + * the PCI device from the EEH subsystem. I/O errors affecting + * this device will no longer be detected after this call; thus, + * i/o errors affecting this slot may leave this device unusable. */ void eeh_remove_device(struct pci_dev *); -#define EEH_DISABLE 0 -#define EEH_ENABLE 1 -#define EEH_RELEASE_LOADSTORE 2 -#define EEH_RELEASE_DMA 3 +/** + * eeh_slot_is_isolated -- return non-zero value if slot is frozen + */ +int eeh_slot_is_isolated (struct pci_dev *dev); /** - * Notifier event flags. + * eeh_ioaddr_is_isolated -- return non-zero value if device at + * io address is frozen. */ -#define EEH_NOTIFY_FREEZE 1 +int eeh_ioaddr_is_isolated(const volatile void __iomem *token); -/** EEH event -- structure holding pci slot data that describes - * a change in the isolation status of a PCI slot. A pointer - * to this struct is passed as the data pointer in a notify callback. - */ -struct eeh_event { - struct list_head list; - struct pci_dev *dev; - struct device_node *dn; - int reset_state; -}; - -/** Register to find out about EEH events. */ -int eeh_register_notifier(struct notifier_block *nb); -int eeh_unregister_notifier(struct notifier_block *nb); +/** + * eeh_slot_error_detail -- record and EEH error condition to the log + * @severity: 1 if temporary, 2 if permanent failure. + * + * Obtains the the EEH error details from the RTAS subsystem, + * and then logs these details with the RTAS error log system. + */ +void eeh_slot_error_detail (struct device_node *dn, int severity); + +/** + * rtas_set_slot_reset -- unfreeze a frozen slot + * + * Clear the EEH-frozen condition on a slot. This routine + * does this by asserting the PCI #RST line for 1/8th of + * a second; this routine will sleep while the adapter is + * being reset. + */ +void rtas_set_slot_reset (struct device_node *dn); + +/** rtas_pci_slot_reset raises/lowers the pci #RST line + * state: 1/0 to raise/lower the #RST + * + * Clear the EEH-frozen condition on a slot. This routine + * asserts the PCI #RST line if the 'state' argument is '1', + * and drops the #RST line if 'state is '0'. This routine is + * safe to call in an interrupt context. + * + */ +void rtas_pci_slot_reset(struct device_node *dn, int state); +void eeh_pci_slot_reset(struct pci_dev *dev, int state); + +/** eeh_pci_slot_availability -- Indicates whether a PCI + * slot is ready to be used. After a PCI reset, it may take a while + * for the PCI fabric to fully reset the comminucations path to the + * given PCI card. This routine can be used to determine how long + * to wait before a PCI slot might become usable. + * + * This routine returns how long to wait (in milliseconds) before + * the slot is expected to be usable. A value of zero means the + * slot is immediately usable. A negavitve value means that the + * slot is permanently disabled. + */ +int eeh_pci_slot_availability(struct pci_dev *dev); + +/** Restore device configuration info across device resets. + */ +void eeh_restore_bars(struct device_node *); +void eeh_pci_restore_bars(struct pci_dev *dev); + +/** + * rtas_configure_bridge -- firmware initialization of pci bridge + * + * Ask the firmware to configure any PCI bridge devices + * located behind the indicated node. Required after a + * pci device reset. + */ +void rtas_configure_bridge(struct device_node *dn); /** * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. @@ -116,7 +169,7 @@ int eeh_unregister_notifier(struct notif #define EEH_IO_ERROR_VALUE(size) (-1UL) #endif -/* +/* * MMIO read/write operations with EEH support. */ static inline u8 eeh_readb(const volatile void __iomem *addr) @@ -238,21 +291,21 @@ static inline void eeh_memcpy_fromio(voi *((u8 *)dest) = *((volatile u8 *)vsrc); __asm__ __volatile__ ("eieio" : : : "memory"); vsrc = (void *)((unsigned long)vsrc + 1); - dest = (void *)((unsigned long)dest + 1); + dest = (void *)((unsigned long)dest + 1); n--; } while(n > 4) { *((u32 *)dest) = *((volatile u32 *)vsrc); __asm__ __volatile__ ("eieio" : : : "memory"); vsrc = (void *)((unsigned long)vsrc + 4); - dest = (void *)((unsigned long)dest + 4); + dest = (void *)((unsigned long)dest + 4); n -= 4; } while(n) { *((u8 *)dest) = *((volatile u8 *)vsrc); __asm__ __volatile__ ("eieio" : : : "memory"); vsrc = (void *)((unsigned long)vsrc + 1); - dest = (void *)((unsigned long)dest + 1); + dest = (void *)((unsigned long)dest + 1); n--; } __asm__ __volatile__ ("sync" : : : "memory"); @@ -274,19 +327,19 @@ static inline void eeh_memcpy_toio(volat while(n && (!EEH_CHECK_ALIGN(vdest, 4) || !EEH_CHECK_ALIGN(src, 4))) { *((volatile u8 *)vdest) = *((u8 *)src); src = (void *)((unsigned long)src + 1); - vdest = (void *)((unsigned long)vdest + 1); + vdest = (void *)((unsigned long)vdest + 1); n--; } while(n > 4) { *((volatile u32 *)vdest) = *((volatile u32 *)src); src = (void *)((unsigned long)src + 4); - vdest = (void *)((unsigned long)vdest + 4); + vdest = (void *)((unsigned long)vdest + 4); n-=4; } while(n) { *((volatile u8 *)vdest) = *((u8 *)src); src = (void *)((unsigned long)src + 1); - vdest = (void *)((unsigned long)vdest + 1); + vdest = (void *)((unsigned long)vdest + 1); n--; } __asm__ __volatile__ ("sync" : : : "memory"); --- include/asm-ppc64/prom.h.linas-orig 2005-04-29 20:32:46.000000000 -0500 +++ include/asm-ppc64/prom.h 2005-05-06 12:28:43.000000000 -0500 @@ -119,6 +119,7 @@ struct property { */ struct pci_controller; struct iommu_table; +struct eeh_recovery_ops; struct device_node { char *name; @@ -137,8 +138,12 @@ struct device_node { int devfn; /* for pci devices */ int eeh_mode; /* See eeh.h for possible EEH_MODEs */ int eeh_config_addr; + int eeh_check_count; /* number of times device driver ignored error */ + int eeh_freeze_count; /* number of times this device froze up. */ + int eeh_is_bridge; /* device is pci-to-pci bridge */ struct pci_controller *phb; /* for pci devices */ struct iommu_table *iommu_table; /* for phb's or bridges */ + u32 config_space[16]; /* saved PCI config space */ struct property *properties; struct device_node *parent; --- include/asm-ppc64/rtas.h.linas-orig 2005-04-29 20:32:32.000000000 -0500 +++ include/asm-ppc64/rtas.h 2005-05-06 12:28:43.000000000 -0500 @@ -243,4 +243,6 @@ extern unsigned long rtas_rmo_buf; #define GLOBAL_INTERRUPT_QUEUE 9005 +extern int rtas_write_config(struct device_node *dn, int where, int size, u32 val); + #endif /* _PPC64_RTAS_H */ --- arch/ppc64/kernel/eeh.c.linas-orig 2005-04-29 20:29:19.000000000 -0500 +++ arch/ppc64/kernel/eeh.c 2005-05-31 15:13:51.000000000 -0500 @@ -1,32 +1,33 @@ /* * eeh.c * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include +#include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -49,8 +50,8 @@ * were "empty": all reads return 0xff's and all writes are silently * ignored. EEH slot isolation events can be triggered by parity * errors on the address or data busses (e.g. during posted writes), - * which in turn might be caused by dust, vibration, humidity, - * radioactivity or plain-old failed hardware. + * which in turn might be caused by low voltage on the bus, dust, + * vibration, humidity, radioactivity or plain-old failed hardware. * * Note, however, that one of the leading causes of EEH slot * freeze events are buggy device drivers, buggy device microcode, @@ -75,22 +76,13 @@ #define BUID_HI(buid) ((buid) >> 32) #define BUID_LO(buid) ((buid) & 0xffffffff) -/* EEH event workqueue setup. */ -static DEFINE_SPINLOCK(eeh_eventlist_lock); -LIST_HEAD(eeh_eventlist); -static void eeh_event_handler(void *); -DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL); - -static struct notifier_block *eeh_notifier_chain; - /* * If a device driver keeps reading an MMIO register in an interrupt * handler after a slot isolation event has occurred, we assume it * is broken and panic. This sets the threshold for how many read * attempts we allow before panicking. */ -#define EEH_MAX_FAILS 1000 -static atomic_t eeh_fail_count; +#define EEH_MAX_FAILS 100000 /* RTAS tokens */ static int ibm_set_eeh_option; @@ -107,6 +99,10 @@ static DEFINE_SPINLOCK(slot_errbuf_lock) static int eeh_error_buf_size; /* System monitoring statistics */ +static DEFINE_PER_CPU(unsigned long, no_device); +static DEFINE_PER_CPU(unsigned long, no_dn); +static DEFINE_PER_CPU(unsigned long, no_cfg_addr); +static DEFINE_PER_CPU(unsigned long, ignored_check); static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); static DEFINE_PER_CPU(unsigned long, false_positives); static DEFINE_PER_CPU(unsigned long, ignored_failures); @@ -225,9 +221,9 @@ pci_addr_cache_insert(struct pci_dev *de while (*p) { parent = *p; piar = rb_entry(parent, struct pci_io_addr_range, rb_node); - if (alo < piar->addr_lo) { + if (ahi < piar->addr_lo) { p = &parent->rb_left; - } else if (ahi > piar->addr_hi) { + } else if (alo > piar->addr_hi) { p = &parent->rb_right; } else { if (dev != piar->pcidev || @@ -246,6 +242,11 @@ pci_addr_cache_insert(struct pci_dev *de piar->pcidev = dev; piar->flags = flags; +#ifdef DEBUG + printk (KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", + alo, ahi, pci_name (dev)); +#endif + rb_link_node(&piar->rb_node, parent, p); rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); @@ -268,9 +269,10 @@ static void __pci_addr_cache_insert_devi /* Skip any devices for which EEH is not enabled. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) { -#ifdef DEBUG - printk(KERN_INFO "PCI: skip building address cache for=%s %s\n", - pci_name(dev), pci_pretty_name(dev)); +// #ifdef DEBUG +#if 1 + printk(KERN_INFO "PCI: skip building address cache for=%s %s %s\n", + pci_name(dev), pci_pretty_name(dev), dn->type); #endif return; } @@ -369,8 +371,12 @@ void pci_addr_cache_remove_device(struct */ void __init pci_addr_cache_build(void) { + struct device_node *dn; struct pci_dev *dev = NULL; + if (!eeh_subsystem_enabled) + return; + spin_lock_init(&pci_io_addr_cache_root.piar_lock); while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { @@ -379,6 +385,17 @@ void __init pci_addr_cache_build(void) continue; } pci_addr_cache_insert_device(dev); + + /* Save the BAR's; firmware doesn't restore these after EEH reset */ + dn = pci_device_to_OF_node(dev); + if (dn) { + int i; + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4, &dn->config_space[i]); + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + dn->eeh_is_bridge = 1; + } } #ifdef DEBUG @@ -390,24 +407,32 @@ void __init pci_addr_cache_build(void) /* --------------------------------------------------------------- */ /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */ -/** - * eeh_register_notifier - Register to find out about EEH events. - * @nb: notifier block to callback on events - */ -int eeh_register_notifier(struct notifier_block *nb) +void eeh_slot_error_detail (struct device_node *dn, int severity) { - return notifier_chain_register(&eeh_notifier_chain, nb); -} + unsigned long flags; + int rc; -/** - * eeh_unregister_notifier - Unregister to an EEH event notifier. - * @nb: notifier block to callback on events - */ -int eeh_unregister_notifier(struct notifier_block *nb) -{ - return notifier_chain_unregister(&eeh_notifier_chain, nb); + if (!dn) return; + + /* Log the error with the rtas logger */ + spin_lock_irqsave(&slot_errbuf_lock, flags); + memset(slot_errbuf, 0, eeh_error_buf_size); + + rc = rtas_call(ibm_slot_error_detail, + 8, 1, NULL, dn->eeh_config_addr, + BUID_HI(dn->phb->buid), + BUID_LO(dn->phb->buid), NULL, 0, + virt_to_phys(slot_errbuf), + eeh_error_buf_size, + severity); + + if (rc == 0) + log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); + spin_unlock_irqrestore(&slot_errbuf_lock, flags); } +EXPORT_SYMBOL(eeh_slot_error_detail); + /** * read_slot_reset_state - Read the reset state of a device node's slot * @dn: device node to read @@ -422,6 +447,7 @@ static int read_slot_reset_state(struct outputs = 4; } else { token = ibm_read_slot_reset_state; + rets[2] = 0; /* fake PE Unavailable info */ outputs = 3; } @@ -430,75 +456,8 @@ static int read_slot_reset_state(struct } /** - * eeh_panic - call panic() for an eeh event that cannot be handled. - * The philosophy of this routine is that it is better to panic and - * halt the OS than it is to risk possible data corruption by - * oblivious device drivers that don't know better. - * - * @dev pci device that had an eeh event - * @reset_state current reset state of the device slot - */ -static void eeh_panic(struct pci_dev *dev, int reset_state) -{ - /* - * XXX We should create a separate sysctl for this. - * - * Since the panic_on_oops sysctl is used to halt the system - * in light of potential corruption, we can use it here. - */ - if (panic_on_oops) - panic("EEH: MMIO failure (%d) on device:%s %s\n", reset_state, - pci_name(dev), pci_pretty_name(dev)); - else { - __get_cpu_var(ignored_failures)++; - printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s %s\n", - reset_state, pci_name(dev), pci_pretty_name(dev)); - } -} - -/** - * eeh_event_handler - dispatch EEH events. The detection of a frozen - * slot can occur inside an interrupt, where it can be hard to do - * anything about it. The goal of this routine is to pull these - * detection events out of the context of the interrupt handler, and - * re-dispatch them for processing at a later time in a normal context. - * - * @dummy - unused - */ -static void eeh_event_handler(void *dummy) -{ - unsigned long flags; - struct eeh_event *event; - - while (1) { - spin_lock_irqsave(&eeh_eventlist_lock, flags); - event = NULL; - if (!list_empty(&eeh_eventlist)) { - event = list_entry(eeh_eventlist.next, struct eeh_event, list); - list_del(&event->list); - } - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); - if (event == NULL) - break; - - printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device " - "%s %s\n", event->reset_state, - pci_name(event->dev), pci_pretty_name(event->dev)); - - atomic_set(&eeh_fail_count, 0); - notifier_call_chain (&eeh_notifier_chain, - EEH_NOTIFY_FREEZE, event); - - __get_cpu_var(slot_resets)++; - - pci_dev_put(event->dev); - kfree(event); - } -} - -/** - * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xE.... + * eeh_token_to_phys - convert I/O address to phys address + * @token i/o address, should be address in the form 0xA.... */ static inline unsigned long eeh_token_to_phys(unsigned long token) { @@ -513,6 +472,18 @@ static inline unsigned long eeh_token_to return pa | (token & (PAGE_SIZE-1)); } + +static inline struct pci_dev * eeh_find_pci_dev(struct device_node *dn) +{ + struct pci_dev *dev = NULL; + for_each_pci_dev(dev) { + if (pci_device_to_OF_node(dev) == dn) + return dev; + } + return NULL; +} + + /** * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze * @dn device node @@ -528,29 +499,37 @@ static inline unsigned long eeh_token_to * * It is safe to call this routine in an interrupt context. */ +extern void disable_irq_nosync(unsigned int); + int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { int ret; int rets[3]; - unsigned long flags; - int rc, reset_state; - struct eeh_event *event; + enum pci_channel_state state; __get_cpu_var(total_mmio_ffs)++; if (!eeh_subsystem_enabled) return 0; - if (!dn) + if (!dn) { + __get_cpu_var(no_dn)++; return 0; + } /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) { + __get_cpu_var(ignored_check)++; +#ifdef DEBUG + printk ("EEH:ignored check for %s %s\n", + pci_pretty_name (dev), dn->full_name); +#endif return 0; } if (!dn->eeh_config_addr) { + __get_cpu_var(no_cfg_addr)++; return 0; } @@ -559,12 +538,18 @@ int eeh_dn_check_failure(struct device_n * slot, we know it's bad already, we don't need to check... */ if (dn->eeh_mode & EEH_MODE_ISOLATED) { - atomic_inc(&eeh_fail_count); - if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) { + dn->eeh_check_count ++; + if (dn->eeh_check_count >= EEH_MAX_FAILS) { + printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n", + dn->eeh_check_count); + dump_stack(); /* re-read the slot reset state */ if (read_slot_reset_state(dn, rets) != 0) rets[0] = -1; /* reset state unknown */ - eeh_panic(dev, rets[0]); + + /* If we are here, then we hit an infinite loop. Stop. */ + panic("EEH: MMIO halt (%d) on device:%s %s\n", rets[0], + pci_name(dev), pci_pretty_name(dev)); } return 0; } @@ -577,53 +562,41 @@ int eeh_dn_check_failure(struct device_n * In any case they must share a common PHB. */ ret = read_slot_reset_state(dn, rets); - if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) { + if (!(ret == 0 && ((rets[1] == 1 && (rets[0] == 2 || rets[0] >= 4)) + || (rets[0] == 5)))) { __get_cpu_var(false_positives)++; return 0; } - /* prevent repeated reports of this failure */ - dn->eeh_mode |= EEH_MODE_ISOLATED; - - reset_state = rets[0]; + /* Note that empty slots will fail; empty slots don't have children... */ + if ((rets[0] == 5) && (dn->child == NULL)) { + __get_cpu_var(false_positives)++; + return 0; + } - spin_lock_irqsave(&slot_errbuf_lock, flags); - memset(slot_errbuf, 0, eeh_error_buf_size); + /* Prevent repeated reports of this failure */ + dn->eeh_mode |= EEH_MODE_ISOLATED; + __get_cpu_var(slot_resets)++; - rc = rtas_call(ibm_slot_error_detail, - 8, 1, NULL, dn->eeh_config_addr, - BUID_HI(dn->phb->buid), - BUID_LO(dn->phb->buid), NULL, 0, - virt_to_phys(slot_errbuf), - eeh_error_buf_size, - 1 /* Temporary Error */); + if (!dev) + dev = eeh_find_pci_dev (dn); - if (rc == 0) - log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); - spin_unlock_irqrestore(&slot_errbuf_lock, flags); + /* Some devices go crazy if irq's are not ack'ed; disable irq now */ + if (dev) + disable_irq_nosync (dev->irq); + + state = pci_channel_io_normal; + if ((rets[0] == 2) || (rets[0] == 4)) + state = pci_channel_io_frozen; + if (rets[0] == 5) + state = pci_channel_io_perm_failure; - printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", - rets[0], dn->name, dn->full_name); - event = kmalloc(sizeof(*event), GFP_ATOMIC); - if (event == NULL) { - eeh_panic(dev, reset_state); - return 1; - } - - event->dev = dev; - event->dn = dn; - event->reset_state = reset_state; - - /* We may or may not be called in an interrupt context */ - spin_lock_irqsave(&eeh_eventlist_lock, flags); - list_add(&event->list, &eeh_eventlist); - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); + peh_send_failure_event (dev, state, rets[2]); /* Most EEH events are due to device driver bugs. Having * a stack trace will help the device-driver authors figure * out what happened. So print that out. */ - dump_stack(); - schedule_work(&eeh_event_wq); + if (rets[0] != 5) dump_stack(); return 0; } @@ -635,7 +608,6 @@ EXPORT_SYMBOL(eeh_dn_check_failure); * @token i/o token, should be address in the form 0xA.... * @val value, should be all 1's (XXX why do we need this arg??) * - * Check for an eeh failure at the given token address. * Check for an EEH failure at the given token address. Call this * routine if the result of a read was all 0xff's and you want to * find out if this is due to an EEH slot freeze event. This routine @@ -643,6 +615,7 @@ EXPORT_SYMBOL(eeh_dn_check_failure); * * Note this routine is safe to call in an interrupt context. */ + unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { unsigned long addr; @@ -652,8 +625,10 @@ unsigned long eeh_check_failure(const vo /* Finding the phys addr + pci device; this is pretty quick. */ addr = eeh_token_to_phys((unsigned long __force) token); dev = pci_get_device_by_addr(addr); - if (!dev) + if (!dev) { + __get_cpu_var(no_device)++; return val; + } dn = pci_device_to_OF_node(dev); eeh_dn_check_failure (dn, dev); @@ -664,6 +639,234 @@ unsigned long eeh_check_failure(const vo EXPORT_SYMBOL(eeh_check_failure); +/* ------------------------------------------------------------- */ +/* The code below deals with error recovery */ + +int +eeh_slot_is_isolated(struct pci_dev *dev) +{ + struct device_node *dn; + dn = pci_device_to_OF_node(dev); + return (dn->eeh_mode & EEH_MODE_ISOLATED); +} +EXPORT_SYMBOL(eeh_slot_is_isolated); + +int +eeh_ioaddr_is_isolated(const volatile void __iomem *token) +{ + unsigned long addr; + struct pci_dev *dev; + int rc; + + addr = eeh_token_to_phys((unsigned long __force) token); + dev = pci_get_device_by_addr(addr); + if (!dev) + return 0; + rc = eeh_slot_is_isolated(dev); + pci_dev_put(dev); + return rc; +} + +/** eeh_pci_slot_reset -- raises/lowers the pci #RST line + * state: 1/0 to raise/lower the #RST + */ +void +eeh_pci_slot_reset(struct pci_dev *dev, int state) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + rtas_pci_slot_reset (dn, state); +} + +/** Return negative value if a permanent error, else return + * a number of milliseconds to wait until the PCI slot is + * ready to be used. + */ +static int +eeh_slot_availability(struct device_node *dn) +{ + int rc; + int rets[3]; + + rc = read_slot_reset_state(dn, rets); + + if (rc) return rc; + + if (rets[1] == 0) return -1; /* EEH is not supported */ + if (rets[0] == 0) return 0; /* Oll Korrect */ + if (rets[0] == 5) { + if (rets[2] == 0) return -1; /* permanently unavailable */ + return rets[2]; /* number of millisecs to wait */ + } + return -1; +} + +int +eeh_pci_slot_availability(struct pci_dev *dev) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + if (!dn) return -1; + + BUG_ON (dn->phb==NULL); + if (dn->phb==NULL) { + printk (KERN_ERR "EEH, checking on slot with no phb dn=%s dev=%s:%s\n", + dn->full_name, pci_name(dev), pci_pretty_name (dev)); + return -1; + } + return eeh_slot_availability (dn); +} + +void +rtas_pci_slot_reset(struct device_node *dn, int state) +{ + int rc; + + if (!dn) + return; + if (!dn->phb) { + printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", dn->full_name); + return; + } + + dn->eeh_mode |= EEH_MODE_RECOVERING; + rc = rtas_call(ibm_set_slot_reset,4,1, NULL, + dn->eeh_config_addr, + BUID_HI(dn->phb->buid), + BUID_LO(dn->phb->buid), + state); + if (rc) { + printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d\n", rc, state); + return; + } + + if (state == 0) + dn->eeh_mode &= ~(EEH_MODE_RECOVERING|EEH_MODE_ISOLATED); +} + +/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second + * dn -- device node to be reset. + */ + +void +rtas_set_slot_reset(struct device_node *dn) +{ + int i, rc; + + rtas_pci_slot_reset (dn, 1); + + /* The PCI bus requires that the reset be held high for at least + * a 100 milliseconds. We wait a bit longer 'just in case'. */ + +#define PCI_BUS_RST_HOLD_TIME_MSEC 250 + msleep (PCI_BUS_RST_HOLD_TIME_MSEC); + rtas_pci_slot_reset (dn, 0); + + /* After a PCI slot has been reset, the PCI Express spec requires + * a 1.5 second idle time for the bus to stabilize, before starting + * up traffic. */ +#define PCI_BUS_SETTLE_TIME_MSEC 1800 + msleep (PCI_BUS_SETTLE_TIME_MSEC); + + /* Now double check with the firmware to make sure the device is + * ready to be used; if not, wait for recovery. */ + for (i=0; i<10; i++) { + rc = eeh_slot_availability (dn); + if (rc <= 0) break; + + msleep (rc+100); + } +} + +EXPORT_SYMBOL(rtas_set_slot_reset); + +void +rtas_configure_bridge(struct device_node *dn) +{ + int token = rtas_token ("ibm,configure-bridge"); + int rc; + + if (token == RTAS_UNKNOWN_SERVICE) + return; + rc = rtas_call(token,3,1, NULL, + dn->eeh_config_addr, + BUID_HI(dn->phb->buid), + BUID_LO(dn->phb->buid)); + if (rc) { + printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", + rc, dn->full_name); + } +} + +EXPORT_SYMBOL(rtas_configure_bridge); + +/* ------------------------------------------------------- */ +/** Save and restore of PCI BARs + * + * Although firmware will set up BARs during boot, it doesn't + * set up device BAR's after a device reset, although it will, + * if requested, set up bridge configuration. Thus, we need to + * configure the PCI devices ourselves. Config-space setup is + * stored in the PCI structures which are normally deleted during + * device removal. Thus, the "save" routine references the + * structures so that they aren't deleted. + */ + +/** + * __restore_bars - Restore the Base Address Registers + * Loads the PCI configuration space base address registers, + * the expansion ROM base address, the latency timer, and etc. + * from the saved values in the device node. + */ +static inline void __restore_bars (struct device_node *dn) +{ + int i; + + if (NULL==dn->phb) return; + for (i=4; i<10; i++) { + rtas_write_config(dn, i*4, 4, dn->config_space[i]); + } + + /* 12 == Expansion ROM Address */ + rtas_write_config(dn, 12*4, 4, dn->config_space[12]); + +#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) +#define SAVED_BYTE(OFF) (((u8 *)(dn->config_space))[BYTE_SWAP(OFF)]) + + rtas_write_config (dn, PCI_CACHE_LINE_SIZE, 1, + SAVED_BYTE(PCI_CACHE_LINE_SIZE)); + + rtas_write_config (dn, PCI_LATENCY_TIMER, 1, + SAVED_BYTE(PCI_LATENCY_TIMER)); + + /* max latency, min grant, interrupt pin and line */ + rtas_write_config(dn, 15*4, 4, dn->config_space[15]); +} + +/** + * eeh_restore_bars - restore the PCI config space info + */ +void eeh_restore_bars(struct device_node *dn) +{ + if (! dn->eeh_is_bridge) + __restore_bars (dn); + + if (dn->child) + eeh_restore_bars (dn->child); +} + +void eeh_pci_restore_bars(struct pci_dev *dev) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + eeh_restore_bars (dn); +} + +/* ------------------------------------------------------------- */ +/* The code below deals with enabling EEH for devices during the + * early boot sequence. EEH must be enabled before any PCI probing + * can be done. + */ + +#define EEH_ENABLE 1 + struct eeh_early_enable_info { unsigned int buid_hi; unsigned int buid_lo; @@ -682,6 +885,8 @@ static void *early_enable_eeh(struct dev int enable; dn->eeh_mode = 0; + dn->eeh_check_count = 0; + dn->eeh_freeze_count = 0; if (status && strcmp(status, "ok") != 0) return NULL; /* ignore devices with bad status */ @@ -743,7 +948,7 @@ static void *early_enable_eeh(struct dev dn->full_name); } - return NULL; + return NULL; } /* @@ -824,11 +1029,13 @@ void eeh_add_device_early(struct device_ struct pci_controller *phb; struct eeh_early_enable_info info; - if (!dn || !eeh_subsystem_enabled) + if (!dn) return; phb = dn->phb; if (NULL == phb || 0 == phb->buid) { - printk(KERN_WARNING "EEH: Expected buid but found none\n"); + printk(KERN_WARNING "EEH: Expected buid but found none for %s\n", + dn->full_name); + dump_stack(); return; } @@ -847,6 +1054,9 @@ EXPORT_SYMBOL(eeh_add_device_early); */ void eeh_add_device_late(struct pci_dev *dev) { + int i; + struct device_node *dn; + if (!dev || !eeh_subsystem_enabled) return; @@ -856,6 +1066,14 @@ void eeh_add_device_late(struct pci_dev #endif pci_addr_cache_insert_device (dev); + + /* Save the BAR's; firmware doesn't restore these after EEH reset */ + dn = pci_device_to_OF_node(dev); + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4, &dn->config_space[i]); + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + dn->eeh_is_bridge = 1; } EXPORT_SYMBOL(eeh_add_device_late); @@ -885,12 +1103,17 @@ static int proc_eeh_show(struct seq_file unsigned int cpu; unsigned long ffs = 0, positives = 0, failures = 0; unsigned long resets = 0; + unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0; for_each_cpu(cpu) { ffs += per_cpu(total_mmio_ffs, cpu); positives += per_cpu(false_positives, cpu); failures += per_cpu(ignored_failures, cpu); resets += per_cpu(slot_resets, cpu); + no_dev += per_cpu(no_device, cpu); + no_dn += per_cpu(no_dn, cpu); + no_cfg += per_cpu(no_cfg_addr, cpu); + no_check += per_cpu(ignored_check, cpu); } if (0 == eeh_subsystem_enabled) { @@ -898,13 +1121,17 @@ static int proc_eeh_show(struct seq_file seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs); } else { seq_printf(m, "EEH Subsystem is enabled\n"); - seq_printf(m, "eeh_total_mmio_ffs=%ld\n" + seq_printf(m, + "no device=%ld\n" + "no device node=%ld\n" + "no config address=%ld\n" + "check not wanted=%ld\n" + "eeh_total_mmio_ffs=%ld\n" "eeh_false_positives=%ld\n" "eeh_ignored_failures=%ld\n" - "eeh_slot_resets=%ld\n" - "eeh_fail_count=%d\n", - ffs, positives, failures, resets, - eeh_fail_count.counter); + "eeh_slot_resets=%ld\n", + no_dev, no_dn, no_cfg, no_check, + ffs, positives, failures, resets); } return 0; --- arch/ppc64/kernel/pSeries_pci.c.linas-orig 2005-04-29 20:33:03.000000000 -0500 +++ arch/ppc64/kernel/pSeries_pci.c 2005-05-06 12:28:43.000000000 -0500 @@ -52,7 +52,7 @@ static int s7a_workaround; extern struct mpic *pSeries_mpic; -static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) +int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) { int returnval = -1; unsigned long buid, addr; @@ -101,7 +101,7 @@ static int rtas_pci_read_config(struct p return PCIBIOS_DEVICE_NOT_FOUND; } -static int rtas_write_config(struct device_node *dn, int where, int size, u32 val) +int rtas_write_config(struct device_node *dn, int where, int size, u32 val) { unsigned long buid, addr; int ret; --- drivers/pci/hotplug/rpaphp.h.linas-orig 2005-04-29 20:26:21.000000000 -0500 +++ drivers/pci/hotplug/rpaphp.h 2005-05-06 12:28:43.000000000 -0500 @@ -118,7 +118,8 @@ extern int rpaphp_enable_pci_slot(struct extern int register_pci_slot(struct slot *slot); extern int rpaphp_unconfig_pci_adapter(struct slot *slot); extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); -extern struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev); +extern void init_eeh_handler (void); +extern void exit_eeh_handler (void); /* rpaphp_core.c */ extern int rpaphp_add_slot(struct device_node *dn); --- drivers/pci/hotplug/rpaphp_core.c.linas-orig 2005-04-29 20:32:16.000000000 -0500 +++ drivers/pci/hotplug/rpaphp_core.c 2005-05-06 12:28:43.000000000 -0500 @@ -460,12 +460,18 @@ static int __init rpaphp_init(void) { info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + /* Get set to handle EEH events. */ + init_eeh_handler(); + /* read all the PRA info from the system */ return init_rpa(); } static void __exit rpaphp_exit(void) { + /* Let EEH know we are going away. */ + exit_eeh_handler(); + cleanup_slots(); } --- drivers/pci/hotplug/rpaphp_pci.c.linas-orig 2005-04-29 20:22:38.000000000 -0500 +++ drivers/pci/hotplug/rpaphp_pci.c 2005-05-16 11:59:30.000000000 -0500 @@ -24,6 +24,7 @@ */ #include #include +#include #include #include #include "../pci.h" /* for pci_add_new_bus */ @@ -63,6 +64,7 @@ int rpaphp_claim_resource(struct pci_dev root ? "Address space collision on" : "No parent found for", resource, dtype, pci_name(dev), res->start, res->end); + dump_stack(); } return err; } @@ -188,6 +190,19 @@ rpaphp_fixup_new_pci_devices(struct pci_ static int rpaphp_pci_config_bridge(struct pci_dev *dev); +static void rpaphp_eeh_add_bus_device(struct pci_bus *bus) +{ + struct pci_dev *dev; + list_for_each_entry(dev, &bus->devices, bus_list) { + eeh_add_device_late(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + struct pci_bus *subbus = dev->subordinate; + if (bus) + rpaphp_eeh_add_bus_device (subbus); + } + } +} + /***************************************************************************** rpaphp_pci_config_slot() will configure all devices under the given slot->dn and return the the first pci_dev. @@ -215,6 +230,8 @@ rpaphp_pci_config_slot(struct device_nod } if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) rpaphp_pci_config_bridge(dev); + + rpaphp_eeh_add_bus_device(bus); } return dev; } @@ -223,7 +240,6 @@ static int rpaphp_pci_config_bridge(stru { u8 sec_busno; struct pci_bus *child_bus; - struct pci_dev *child_dev; dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev)); @@ -240,11 +256,7 @@ static int rpaphp_pci_config_bridge(stru /* do pci_scan_child_bus */ pci_scan_child_bus(child_bus); - list_for_each_entry(child_dev, &child_bus->devices, bus_list) { - eeh_add_device_late(child_dev); - } - - /* fixup new pci devices without touching bus struct */ + /* Fixup new pci devices without touching bus struct */ rpaphp_fixup_new_pci_devices(child_bus, 0); /* Make the discovered devices available */ @@ -282,7 +294,7 @@ static void print_slot_pci_funcs(struct return; } #else -static void print_slot_pci_funcs(struct slot *slot) +static inline void print_slot_pci_funcs(struct slot *slot) { return; } @@ -364,7 +376,6 @@ static void rpaphp_eeh_remove_bus_device if (pdev) rpaphp_eeh_remove_bus_device(pdev); } - } return; } @@ -566,36 +577,3 @@ exit: return retval; } -struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev) -{ - struct list_head *tmp, *n; - struct slot *slot; - - list_for_each_safe(tmp, n, &rpaphp_slot_head) { - struct pci_bus *bus; - struct list_head *ln; - - slot = list_entry(tmp, struct slot, rpaphp_slot_list); - if (slot->bridge == NULL) { - if (slot->dev_type == PCI_DEV) { - printk(KERN_WARNING "PCI slot missing bridge %s %s \n", - slot->name, slot->location); - } - continue; - } - - bus = slot->bridge->subordinate; - if (!bus) { - continue; /* should never happen? */ - } - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev == dev) - return slot->hotplug_slot; - } - } - - return NULL; -} - -EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot); --- drivers/pci/hotplug/rpaphp_eeh.c.linas-orig 2005-05-16 11:52:15.000000000 -0500 +++ drivers/pci/hotplug/rpaphp_eeh.c 2005-05-31 11:20:06.000000000 -0500 @@ -0,0 +1,354 @@ +/* + * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform. + * Copyright (C) 2004, 2005 Linas Vepstas + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" +#include "rpaphp.h" + +/** + * pci_search_bus_for_dev - return 1 if device is under this bus, else 0 + * @bus: the bus to search for this device. + * @dev: the pci device we are looking for. + * + * XXX should this be moved to drivers/pci/search.c ? + */ +static int pci_search_bus_for_dev (struct pci_bus *bus, struct pci_dev *dev) +{ + struct list_head *ln; + + if (!bus) return 0; + + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *pdev = pci_dev_b(ln); + if (pdev == dev) + return 1; + if (pdev->subordinate) { + int rc; + rc = pci_search_bus_for_dev (pdev->subordinate, dev); + if (rc) + return 1; + } + } + return 0; +} + +/** pci_walk_bus - walk bus under this device, calling callback. + * @top device whose peers should be walked + * @cb callback to be called for each device found + * @userdata arbitrary pointer to be passed to callback. + * + * Walk the bus on which this device sits, including any + * bridged devices on busses under this bus. Call the provided + * callback on each device found. + */ +typedef void (*pci_buswalk_cb)(struct pci_dev *, void *); + +static void +pci_walk_bus (struct pci_dev *top, pci_buswalk_cb cb, void *userdata) +{ + struct pci_dev *dev, *tmp; + + spin_lock(&pci_bus_lock); + list_for_each_entry_safe (dev, tmp, &top->bus->devices, bus_list) { + pci_dev_get(dev); + spin_unlock(&pci_bus_lock); + + /* run device routines with the bus unlocked */ + cb (dev, userdata); + if (dev->subordinate) { + pci_walk_bus (pci_dev_b(&dev->subordinate->devices), cb, userdata); + } + spin_lock(&pci_bus_lock); + pci_dev_put(dev); + } + spin_unlock(&pci_bus_lock); +} + +/** + * rpaphp_find_slot - find and return the slot holding the device + * @dev: pci device for which we want the slot structure. + */ +static struct slot *rpaphp_find_slot(struct pci_dev *dev) +{ + struct list_head *tmp, *n; + struct slot *slot; + + list_for_each_safe(tmp, n, &rpaphp_slot_head) { + struct pci_bus *bus; + + slot = list_entry(tmp, struct slot, rpaphp_slot_list); + + /* PHB's don't have bridges. */ + if (slot->bridge == NULL) + continue; + + /* The PCI device could be the slot itself. */ + if (slot->bridge == dev) + return slot; + + bus = slot->bridge->subordinate; + if (!bus) { + printk (KERN_WARNING "PCI bridge is missing bus: %s %s\n", + pci_name (slot->bridge), pci_pretty_name (slot->bridge)); + continue; /* should never happen? */ + } + + if (pci_search_bus_for_dev (bus, dev)) + return slot; + } + return NULL; +} + +/* ------------------------------------------------------- */ +/** eeh_report_error - report an EEH error to each device, + * collect up and merge the device responses. + */ + +static void eeh_report_error(struct pci_dev *dev, void *userdata) +{ + enum pcierr_result rc, *res = userdata; + + if (dev->driver->err_handler.error_detected) { + rc = dev->driver->err_handler.error_detected (dev, pci_channel_io_frozen); + if (*res == PCIERR_RESULT_NONE) *res = rc; + if (*res == PCIERR_RESULT_NEED_RESET) return; + if (*res == PCIERR_RESULT_DISCONNECT && + rc == PCIERR_RESULT_NEED_RESET) *res = rc; + } +} + +/** eeh_report_reset -- tell this device that the pci slot + * has been reset. + */ + +static void eeh_report_reset(struct pci_dev *dev, void *userdata) +{ + if (dev->driver->err_handler.slot_reset) + dev->driver->err_handler.slot_reset (dev); +} + +static void eeh_report_resume(struct pci_dev *dev, void *userdata) +{ + if (dev->driver->err_handler.resume) + dev->driver->err_handler.resume (dev); +} + +static void eeh_report_failure(struct pci_dev *dev, void *userdata) +{ + if (dev->driver->err_handler.error_detected) + dev->driver->err_handler.error_detected (dev, pci_channel_io_perm_failure); +} + +/* ------------------------------------------------------- */ +/** + * handle_eeh_events -- reset a PCI device after hard lockup. + * + * pSeries systems will isolate a PCI slot if the PCI-Host + * bridge detects address or data parity errors, DMA's + * occuring to wild addresses (which usually happen due to + * bugs in device drivers or in PCI adapter firmware). + * Slot isolations also occur if #SERR, #PERR or other misc + * PCI-related errors are detected. + * + * Recovery process consists of unplugging the device driver + * (which generated hotplug events to userspace), then issuing + * a PCI #RST to the device, then reconfiguring the PCI config + * space for all bridges & devices under this slot, and then + * finally restarting the device drivers (which cause a second + * set of hotplug events to go out to userspace). + */ + +int eeh_reset_device (struct pci_dev *dev, struct device_node *dn, int reconfig) +{ + struct slot *frozen_slot= NULL; + + if (!dev) + return 1; + + if (reconfig) + frozen_slot = rpaphp_find_slot(dev); + + if (reconfig && frozen_slot) rpaphp_unconfig_pci_adapter (frozen_slot); + + /* Reset the pci controller. (Asserts RST#; resets config space). + * Reconfigure bridges and devices */ + rtas_set_slot_reset (dn->child); + rtas_configure_bridge(dn); + eeh_restore_bars(dn->child); + + enable_irq (dev->irq); + + /* Give the system 5 seconds to finish running the user-space + * hotplug scripts, e.g. ifdown for ethernet. Yes, this is a hack, + * but if we don't do this, weird things happen. + */ + if (reconfig && frozen_slot) { + ssleep (5); + rpaphp_enable_pci_slot (frozen_slot); + } + return 0; +} + +/* The longest amount of time to wait for a pci device + * to come back on line, in seconds. + */ +#define MAX_WAIT_FOR_RECOVERY 15 + +int handle_eeh_events (struct notifier_block *self, + unsigned long reason, void *ev) +{ + int freeze_count=0; + struct device_node *frozen_device; + struct peh_event *event = ev; + struct pci_dev *dev = event->dev; + int perm_failure = 0; + + if (!dev) + { + printk ("EEH: EEH error caught, but no PCI device specified!\n"); + return 1; + } + + frozen_device = pci_bus_to_OF_node(dev->bus); + if (!frozen_device) + { + printk (KERN_ERR "EEH: Cannot find PCI controller for %s %s\n", + pci_name(dev), pci_pretty_name (dev)); + + return 1; + } + BUG_ON (frozen_device->phb==NULL); + + /* We get "permanent failure" messages on empty slots. + * These are false alarms. Empty slots have no child dn. */ + if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL)) + return 0; + + if (frozen_device) + freeze_count = frozen_device->eeh_freeze_count; + freeze_count ++; + if (freeze_count > EEH_MAX_ALLOWED_FREEZES) + perm_failure = 1; + + /* If the reset state is a '5' and the time to reset is 0 (infinity) + * or is more then 15 seconds, then mark this as a permanent failure. + */ + if ((event->state == pci_channel_io_perm_failure) && + ((event->time_unavail <= 0) || + (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000))) + perm_failure = 1; + + /* Log the error with the rtas logger. */ + if (perm_failure) { + /* + * About 90% of all real-life EEH failures in the field + * are due to poorly seated PCI cards. Only 10% or so are + * due to actual, failed cards. + */ + printk (KERN_ERR + "EEH: device %s:%s has failed %d times \n" + "and has been permanently disabled. Please try reseating\n" + "this device or replacing it.\n", + pci_name (dev), + pci_pretty_name (dev), + freeze_count); + + eeh_slot_error_detail (frozen_device, 2 /* Permanent Error */); + + /* Notify all devices that they're about to go down. */ + pci_walk_bus (dev, eeh_report_failure, 0); + + /* If there's a hotplug slot, unconfigure it */ + // XXX we need alternate way to deconfigure non-hotplug slots. + struct slot * frozen_slot = rpaphp_find_slot(dev); + if (frozen_slot) + rpaphp_unconfig_pci_adapter (frozen_slot); + return 1; + } else { + eeh_slot_error_detail (frozen_device, 1 /* Temporary Error */); + } + + printk (KERN_WARNING + "EEH: This device has failed %d times since last reboot: %s:%s\n", + freeze_count, + pci_name (dev), + pci_pretty_name (dev)); + + /* Walk the various device drivers attached to this slot, + * letting each know about the EEH bug. + */ + enum pcierr_result result = PCIERR_RESULT_NONE; + pci_walk_bus (dev, eeh_report_error, &result); + + /* If all device drivers were EEH-unaware, then pci hotplug + * the device, and hope that clears the error. */ + if (result == PCIERR_RESULT_NONE) { + eeh_reset_device (dev, frozen_device, 1); + } + + /* If any device called out for a reset, then reset the slot */ + if (result == PCIERR_RESULT_NEED_RESET) { + eeh_reset_device (dev, frozen_device, 0); + pci_walk_bus (dev, eeh_report_reset, 0); + } + + /* If all devices reported they can proceed, the re-enable PIO */ + if (result == PCIERR_RESULT_CAN_RECOVER) { + /* XXX Not supported; we brute-force reset the device */ + eeh_reset_device (dev, frozen_device, 0); + pci_walk_bus (dev, eeh_report_reset, 0); + } + + /* Tell all device drivers that they can resume operations */ + pci_walk_bus (dev, eeh_report_resume, 0); + + /* Store the freeze count with the pci adapter, and not the slot. + * This way, if the device is replaced, the count is cleared. + */ + frozen_device->eeh_freeze_count = freeze_count; + + return 1; +} + +static struct notifier_block eeh_block; + +void __init init_eeh_handler (void) +{ + eeh_block.notifier_call = handle_eeh_events; + peh_register_notifier (&eeh_block); +} + +void __exit exit_eeh_handler (void) +{ + peh_unregister_notifier (&eeh_block); +} + --- drivers/pci/hotplug/Makefile.linas-orig 2005-04-29 20:29:50.000000000 -0500 +++ drivers/pci/hotplug/Makefile 2005-05-16 11:53:52.000000000 -0500 @@ -41,6 +41,7 @@ acpiphp-objs := acpiphp_core.o \ acpiphp_res.o rpaphp-objs := rpaphp_core.o \ + rpaphp_eeh.o \ rpaphp_pci.o \ rpaphp_slot.o \ rpaphp_vio.o From johnrose at austin.ibm.com Wed Jun 1 06:52:07 2005 From: johnrose at austin.ibm.com (John Rose) Date: Tue, 31 May 2005 15:52:07 -0500 Subject: [PATCH]: PCI Error Recovery Implementation In-Reply-To: <20050531203028.GD31199@austin.ibm.com> References: <20050531203028.GD31199@austin.ibm.com> Message-ID: <1117572727.7775.11.camel@sinatra.austin.ibm.com> Hi Linas/Greg/Everyone- +int handle_eeh_events (struct notifier_block *self, + unsigned long reason, void *ev) At the risk of sounding like a broken record, I don't think that this belongs in the RPA PCI Hotplug driver. This bit of code _uses_ PCI Hotplug rather than implementing it, and thus stands out from the rest of the module. Not to mention that it uses EEH-specific stuff that doesn't belong here. I'm in the midst of reducing the codebase of this module significantly, and this adds more unrelated stuff to an already cluttered module. I think the PCI hotplug driver could register enable/disable functions with eeh.c, and that the handle_events() code should reside there. If someone has a good technical explanation of why this is bad, please chime in. Thanks- John From raffi at raffi.at Wed Jun 1 07:26:38 2005 From: raffi at raffi.at (Raffael Himmelreich) Date: Tue, 31 May 2005 23:26:38 +0200 Subject: SCSI timeouts (was: Re: RS/6000 7017-S7A hangs on boot) In-Reply-To: <20050522205427.GE20174@krispykreme> References: <20050522201816.GA8254@exception.at> <20050522205427.GE20174@krispykreme> Message-ID: <20050531212638.GA11249@exception.at> Hi, thanks for your reply and sorry for my delay, but my access to the machine is rather limited. Anton Blanchard wrote: > Is xmon on? You might get some > more info on the oops if xmon is turned off (it looks like it hung). Heya. Seems like this was the point. But now I am facing strange SCSI timeouts. Any ideas? (these SCSI devices work well under AIX) > > cpu 0x1: Vector: 300 (Data Access) at [c00000003ff87b70] > > pc: c00000000002de3c > Can you look up the pc in your System.map? Hum, I recompiled the kernel as you suggested and didn't backup the System.map. But I can remember that this address didn't point to any beginning symbol address. If you are interested in this issue I will rebuild the kernel. best regards, raffi Boot log goes here: zImage starting: loaded at 0x400000 Allocating 0x80a000 bytes for kernel ... gunzipping (0x1c00000 <- 0x407000:0x695dc7)...done 0x6b5bd8 bytes 0xde98 bytes of heap consumed, max in use 0xa294 OF stdout device is: /pci at f8400000/isa at f/serial at i3f8 command line: root=/dev/fd0 memory layout at init: memory_limit : 0000000000000000 (16 MB aligned) alloc_bottom : 000000000231e000 alloc_top : 0000000040000000 alloc_top_hi : 0000000140000000 rmo_top : 0000000040000000 ram_top : 0000000140000000 Looking for displays opening PHB /pci at f8400000... done opening PHB /pci at f8500000... done opening PHB /pci at f8600000... done opening PHB /pci at f8700000... done instantiating rtas at 0x000000003ffd7000... done 0000000000000001 : starting cpu hw idx 0000000000000001... done 0000000000000002 : starting cpu hw idx 0000000000000002... done 0000000000000003 : starting cpu hw idx 0000000000000003... done WARNING: maximum CPUs (1) exceeded: ignoring extras copying OF device tree ... Building dt strings... Building dt structure... Device tree strings 0x000000000241f000 -> 0x000000000241fd7c Device tree struct 0x0000000002420000 -> 0x0000000002429000 Calling quiesce ... returning from prom_init firmware_features = 0x0 Starting Linux PPC64 2.6.12-rc5 ----------------------------------------------------- ppc64_pft_size = 0x1a ppc64_debug_switch = 0x0 ppc64_interrupt_controller = 0x1 systemcfg = 0xc0000000004d0000 systemcfg->platform = 0x100 systemcfg->processorCount = 0x0 systemcfg->physicalMemorySize = 0xc0000000 ppc64_caches.dcache_line_size = 0x80 ppc64_caches.icache_line_size = 0x80 htab_address = 0xc000000138000000 htab_hash_mask = 0x7ffff ----------------------------------------------------- [boot]0100 MM Init IO Hole assumed to be 80000000 -> ffffffff [boot]0100 MM Init Done Linux version 2.6.12-rc5 (root at localhost.localdomain) (gcc version 3.4.3) #2 Wed May 25 14:20:01 CEST 2005 [boot]0012 Setup Arch Syscall map setup, 236 32 bits and 212 64 bits syscalls mpic: Setting up MPIC " MPIC " version at ffc00000, max 1 CPUs mpic: ISU size: 16, shift: 4, mask: f No ramdisk, default root is /dev/sda2 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 PPC64 nvram contains 122880 bytes Using default idle loop Top of RAM: 0x140000000, Total RAM: 0xc0000000 Memory hole size: 2048MB [boot]0015 Setup Done Built 1 zonelists Kernel command line: root=/dev/fd0 mpic: Initializing for 64 sources PID hash table entries: 4096 (order: 12, 131072 bytes) time_init: decrementer frequency = 262.731521 MHz time_init: processor frequency = 251.781200 MHz firmware_features = 0x0 Starting Linux PPC64 2.6.12-rc5 ----------------------------------------------------- ppc64_pft_size = 0x1a ppc64_debug_switch = 0x0 ppc64_interrupt_controller = 0x1 systemcfg = 0xc0000000004d0000 systemcfg->platform = 0x100 systemcfg->processorCount = 0x0 systemcfg->physicalMemorySize = 0xc0000000 ppc64_caches.dcache_line_size = 0x80 ppc64_caches.icache_line_size = 0x80 htab_address = 0xc000000138000000 htab_hash_mask = 0x7ffff ----------------------------------------------------- [boot]0100 MM Init IO Hole assumed to be 80000000 -> ffffffff [boot]0100 MM Init Done Linux version 2.6.12-rc5 (root at localhost.localdomain) (gcc version 3.4.3) #2 Wed May 25 14:20:01 CEST 2005 [boot]0012 Setup Arch Syscall map setup, 236 32 bits and 212 64 bits syscalls mpic: Setting up MPIC " MPIC " version at ffc00000, max 1 CPUs mpic: ISU size: 16, shift: 4, mask: f No ramdisk, default root is /dev/sda2 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 Python workaround: reg0: 218e3b88 PPC64 nvram contains 122880 bytes Using default idle loop Top of RAM: 0x140000000, Total RAM: 0xc0000000 Memory hole size: 2048MB [boot]0015 Setup Done Built 1 zonelists Kernel command line: root=/dev/fd0 mpic: Initializing for 64 sources PID hash table entries: 4096 (order: 12, 131072 bytes) time_init: decrementer frequency = 262.731521 MHz time_init: processor frequency = 251.781200 MHz Console: colour dummy device 80x25 Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes) Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes) Memory: 2961152k/5242880k available (4040k kernel code, 2281068k reserved, 1880k data, 415k bss, 316k init) Mount-cache hash table entries: 256 NET: Registered protocol family 16 PCI: Probing PCI hardware IOMMU table initialized, virtual merging enabled mapping IO e0000000 -> e000000000000000, size: 2000000 mapping IO e2000000 -> e000000002000000, size: 800000 mapping IO e2800000 -> e000000002800000, size: 800000 mapping IO e3000000 -> e000000003000000, size: 800000 ISA bridge at 0000:00:0f.0 PCI: Probing PCI hardware done SCSI subsystem initialized usbcore: registered new driver usbfs usbcore: registered new driver hub i/pSeries Real Time Clock Driver v1.1 RTAS daemon started audit: initializing netlink socket (disabled) audit(343277964121.727:0): initialized Total HugeTLB memory allocated, 0 Initializing Cryptographic API HVSI: registered 0 devices Initializing IBM hvcs (Hypervisor Virtual Console Server) Driver HVCS: driver module inserted. serio: i8042 AUX port at 0x60,0x64 irq 12 serio: i8042 KBD port at 0x60,0x64 irq 1 Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A ttyS1 at I/O 0x2f8 (irq = 3) is a 16550A io scheduler noop registered io scheduler anticipatory registered io scheduler deadline registered io scheduler cfq registered Floppy drive(s): fd0 is 2.88M FDC 0 is a National Semiconductor PC87306 RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize loop: loaded (max 8 devices) Intel(R) PRO/1000 Network Driver - version 5.7.6-k2 Copyright (c) 1999-2004 Intel Corporation. pcnet32.c:v1.30i 06.28.2004 tsbogend at alpha.franken.de pcnet32: PCnet/PCI II 79C970A at 0x1fff400, warning: CSR address invalid, using instead PROM address of 02 07 01 23 fc e8 assigned IRQ 22. eth0: registered as PCnet/PCI II 79C970A pcnet32: PCnet/FAST 79C971 at 0x27ff400, 00 20 35 35 74 a5 tx_start_pt(0x0c00):~220 bytes, BCR18(68e2):BurstWrEn BurstRdEn DWordIO NoUFlow SRAMSIZE=0x7f00, SRAM_BND=0x4000, assigned IRQ 38. eth1: registered as PCnet/FAST 79C971 pcnet32: PCnet/FAST 79C971 at 0x2ffec00, warning: CSR address invalid, using instead PROM address of 00 04 ac de 92 54 tx_start_pt(0x0c00):~220 bytes, BCR18(6861):BurstWrEn BurstRdEn NoUFlow SRAMSIZE=0x7f00, SRAM_BND=0x4000, assigned IRQ 54. eth2: registered as PCnet/FAST 79C971 pcnet32: 3 cards_found. e100: Intel(R) PRO/100 Network Driver, 3.3.6-k2-NAPI e100: Copyright(c) 1999-2004 Intel Corporation drivers/net/ibmveth.c: ibmveth: IBM i/pSeries Virtual Ethernet Driver 1.03 netconsole: not configured, aborting Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2 ide: Assuming 33MHz system bus speed for PIO modes; override with idebus=xx sym0: <825a> rev 0x13 at pci 0000:00:0b.0 irq 25 sym0: No NVRAM, ID 7, Fast-10, SE, parity checking sym0: SCSI BUS has been reset. scsi0 : sym-2.2.0 0:0:0:0: ABORT operation started. 0:0:0:0: ABORT operation timed-out. 0:0:0:0: DEVICE RESET operation started. 0:0:0:0: DEVICE RESET operation timed-out. 0:0:0:0: BUS RESET operation started. 0:0:0:0: BUS RESET operation timed-out. 0:0:0:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 0 lun 0 0:0:1:0: ABORT operation started. 0:0:1:0: ABORT operation timed-out. 0:0:1:0: DEVICE RESET operation started. 0:0:1:0: DEVICE RESET operation timed-out. 0:0:1:0: BUS RESET operation started. 0:0:1:0: BUS RESET operation timed-out. 0:0:1:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 1 lun 0 0:0:2:0: ABORT operation started. 0:0:2:0: ABORT operation timed-out. 0:0:2:0: DEVICE RESET operation started. 0:0:2:0: DEVICE RESET operation timed-out. 0:0:2:0: BUS RESET operation started. 0:0:2:0: BUS RESET operation timed-out. 0:0:2:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 2 lun 0 0:0:3:0: ABORT operation started. 0:0:3:0: ABORT operation timed-out. 0:0:3:0: DEVICE RESET operation started. 0:0:3:0: DEVICE RESET operation timed-out. 0:0:3:0: BUS RESET operation started. 0:0:3:0: BUS RESET operation timed-out. 0:0:3:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 3 lun 0 0:0:4:0: ABORT operation started. 0:0:4:0: ABORT operation timed-out. 0:0:4:0: DEVICE RESET operation started. 0:0:4:0: DEVICE RESET operation timed-out. 0:0:4:0: BUS RESET operation started. 0:0:4:0: BUS RESET operation timed-out. 0:0:4:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 4 lun 0 0:0:5:0: ABORT operation started. 0:0:5:0: ABORT operation timed-out. 0:0:5:0: DEVICE RESET operation started. 0:0:5:0: DEVICE RESET operation timed-out. 0:0:5:0: BUS RESET operation started. 0:0:5:0: BUS RESET operation timed-out. 0:0:5:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 5 lun 0 0:0:6:0: ABORT operation started. 0:0:6:0: ABORT operation timed-out. 0:0:6:0: DEVICE RESET operation started. 0:0:6:0: DEVICE RESET operation timed-out. 0:0:6:0: BUS RESET operation started. 0:0:6:0: BUS RESET operation timed-out. 0:0:6:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 6 lun 0 0:0:8:0: ABORT operation started. 0:0:8:0: ABORT operation timed-out. 0:0:8:0: DEVICE RESET operation started. 0:0:8:0: DEVICE RESET operation timed-out. 0:0:8:0: BUS RESET operation started. 0:0:8:0: BUS RESET operation timed-out. 0:0:8:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 8 lun 0 0:0:9:0: ABORT operation started. 0:0:9:0: ABORT operation timed-out. 0:0:9:0: DEVICE RESET operation started. 0:0:9:0: DEVICE RESET operation timed-out. 0:0:9:0: BUS RESET operation started. 0:0:9:0: BUS RESET operation timed-out. 0:0:9:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 9 lun 0 0:0:10:0: ABORT operation started. 0:0:10:0: ABORT operation timed-out. 0:0:10:0: DEVICE RESET operation started. 0:0:10:0: DEVICE RESET operation timed-out. 0:0:10:0: BUS RESET operation started. 0:0:10:0: BUS RESET operation timed-out. 0:0:10:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 10 lun 0 0:0:11:0: ABORT operation started. 0:0:11:0: ABORT operation timed-out. 0:0:11:0: DEVICE RESET operation started. 0:0:11:0: DEVICE RESET operation timed-out. 0:0:11:0: BUS RESET operation started. 0:0:11:0: BUS RESET operation timed-out. 0:0:11:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 11 lun 0 0:0:12:0: ABORT operation started. 0:0:12:0: ABORT operation timed-out. 0:0:12:0: DEVICE RESET operation started. 0:0:12:0: DEVICE RESET operation timed-out. 0:0:12:0: BUS RESET operation started. 0:0:12:0: BUS RESET operation timed-out. 0:0:12:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 12 lun 0 0:0:13:0: ABORT operation started. 0:0:13:0: ABORT operation timed-out. 0:0:13:0: DEVICE RESET operation started. 0:0:13:0: DEVICE RESET operation timed-out. 0:0:13:0: BUS RESET operation started. 0:0:13:0: BUS RESET operation timed-out. 0:0:13:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 13 lun 0 0:0:14:0: ABORT operation started. 0:0:14:0: ABORT operation timed-out. 0:0:14:0: DEVICE RESET operation started. 0:0:14:0: DEVICE RESET operation timed-out. 0:0:14:0: BUS RESET operation started. 0:0:14:0: BUS RESET operation timed-out. 0:0:14:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 14 lun 0 0:0:15:0: ABORT operation started. 0:0:15:0: ABORT operation timed-out. 0:0:15:0: DEVICE RESET operation started. 0:0:15:0: DEVICE RESET operation timed-out. 0:0:15:0: BUS RESET operation started. 0:0:15:0: BUS RESET operation timed-out. 0:0:15:0: HOST RESET operation started. sym0: SCSI BUS has been reset. 0:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 0 channel 0 id 15 lun 0 sym1: <875> rev 0x3 at pci 0000:00:0d.0 irq 23 sym1: No NVRAM, ID 7, Fast-20, SE, parity checking sym1: SCSI BUS has been reset. scsi1 : sym-2.2.0 1:0:0:0: ABORT operation started. 1:0:0:0: ABORT operation timed-out. 1:0:0:0: DEVICE RESET operation started. 1:0:0:0: DEVICE RESET operation timed-out. 1:0:0:0: BUS RESET operation started. 1:0:0:0: BUS RESET operation timed-out. 1:0:0:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 0 lun 0 1:0:1:0: ABORT operation started. 1:0:1:0: ABORT operation timed-out. 1:0:1:0: DEVICE RESET operation started. 1:0:1:0: DEVICE RESET operation timed-out. 1:0:1:0: BUS RESET operation started. 1:0:1:0: BUS RESET operation timed-out. 1:0:1:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 1 lun 0 1:0:2:0: ABORT operation started. 1:0:2:0: ABORT operation timed-out. 1:0:2:0: DEVICE RESET operation started. 1:0:2:0: DEVICE RESET operation timed-out. 1:0:2:0: BUS RESET operation started. 1:0:2:0: BUS RESET operation timed-out. 1:0:2:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 2 lun 0 1:0:3:0: ABORT operation started. 1:0:3:0: ABORT operation timed-out. 1:0:3:0: DEVICE RESET operation started. 1:0:3:0: DEVICE RESET operation timed-out. 1:0:3:0: BUS RESET operation started. 1:0:3:0: BUS RESET operation timed-out. 1:0:3:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 3 lun 0 1:0:4:0: ABORT operation started. 1:0:4:0: ABORT operation timed-out. 1:0:4:0: DEVICE RESET operation started. 1:0:4:0: DEVICE RESET operation timed-out. 1:0:4:0: BUS RESET operation started. 1:0:4:0: BUS RESET operation timed-out. 1:0:4:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 4 lun 0 1:0:5:0: ABORT operation started. 1:0:5:0: ABORT operation timed-out. 1:0:5:0: DEVICE RESET operation started. 1:0:5:0: DEVICE RESET operation timed-out. 1:0:5:0: BUS RESET operation started. 1:0:5:0: BUS RESET operation timed-out. 1:0:5:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 5 lun 0 1:0:6:0: ABORT operation started. 1:0:6:0: ABORT operation timed-out. 1:0:6:0: DEVICE RESET operation started. 1:0:6:0: DEVICE RESET operation timed-out. 1:0:6:0: BUS RESET operation started. 1:0:6:0: BUS RESET operation timed-out. 1:0:6:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 6 lun 0 1:0:8:0: ABORT operation started. 1:0:8:0: ABORT operation timed-out. 1:0:8:0: DEVICE RESET operation started. 1:0:8:0: DEVICE RESET operation timed-out. 1:0:8:0: BUS RESET operation started. 1:0:8:0: BUS RESET operation timed-out. 1:0:8:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 8 lun 0 1:0:9:0: ABORT operation started. 1:0:9:0: ABORT operation timed-out. 1:0:9:0: DEVICE RESET operation started. 1:0:9:0: DEVICE RESET operation timed-out. 1:0:9:0: BUS RESET operation started. 1:0:9:0: BUS RESET operation timed-out. 1:0:9:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 9 lun 0 1:0:10:0: ABORT operation started. 1:0:10:0: ABORT operation timed-out. 1:0:10:0: DEVICE RESET operation started. 1:0:10:0: DEVICE RESET operation timed-out. 1:0:10:0: BUS RESET operation started. 1:0:10:0: BUS RESET operation timed-out. 1:0:10:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 10 lun 0 1:0:11:0: ABORT operation started. 1:0:11:0: ABORT operation timed-out. 1:0:11:0: DEVICE RESET operation started. 1:0:11:0: DEVICE RESET operation timed-out. 1:0:11:0: BUS RESET operation started. 1:0:11:0: BUS RESET operation timed-out. 1:0:11:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 11 lun 0 1:0:12:0: ABORT operation started. 1:0:12:0: ABORT operation timed-out. 1:0:12:0: DEVICE RESET operation started. 1:0:12:0: DEVICE RESET operation timed-out. 1:0:12:0: BUS RESET operation started. 1:0:12:0: BUS RESET operation timed-out. 1:0:12:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 12 lun 0 1:0:13:0: ABORT operation started. 1:0:13:0: ABORT operation timed-out. 1:0:13:0: DEVICE RESET operation started. 1:0:13:0: DEVICE RESET operation timed-out. 1:0:13:0: BUS RESET operation started. 1:0:13:0: BUS RESET operation timed-out. 1:0:13:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 13 lun 0 1:0:14:0: ABORT operation started. 1:0:14:0: ABORT operation timed-out. 1:0:14:0: DEVICE RESET operation started. 1:0:14:0: DEVICE RESET operation timed-out. 1:0:14:0: BUS RESET operation started. 1:0:14:0: BUS RESET operation timed-out. 1:0:14:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 14 lun 0 1:0:15:0: ABORT operation started. 1:0:15:0: ABORT operation timed-out. 1:0:15:0: DEVICE RESET operation started. 1:0:15:0: DEVICE RESET operation timed-out. 1:0:15:0: BUS RESET operation started. 1:0:15:0: BUS RESET operation timed-out. 1:0:15:0: HOST RESET operation started. sym1: SCSI BUS has been reset. 1:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 1 channel 0 id 15 lun 0 sym2: <825a> rev 0x13 at pci 0001:10:0d.0 irq 39 sym2: No NVRAM, ID 7, Fast-10, SE, parity checking sym2: SCSI BUS has been reset. scsi2 : sym-2.2.0 2:0:0:0: ABORT operation started. 2:0:0:0: ABORT operation timed-out. 2:0:0:0: DEVICE RESET operation started. 2:0:0:0: DEVICE RESET operation timed-out. 2:0:0:0: BUS RESET operation started. 2:0:0:0: BUS RESET operation timed-out. 2:0:0:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 0 lun 0 2:0:1:0: ABORT operation started. 2:0:1:0: ABORT operation timed-out. 2:0:1:0: DEVICE RESET operation started. 2:0:1:0: DEVICE RESET operation timed-out. 2:0:1:0: BUS RESET operation started. 2:0:1:0: BUS RESET operation timed-out. 2:0:1:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 1 lun 0 2:0:2:0: ABORT operation started. 2:0:2:0: ABORT operation timed-out. 2:0:2:0: DEVICE RESET operation started. 2:0:2:0: DEVICE RESET operation timed-out. 2:0:2:0: BUS RESET operation started. 2:0:2:0: BUS RESET operation timed-out. 2:0:2:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 2 lun 0 2:0:3:0: ABORT operation started. 2:0:3:0: ABORT operation timed-out. 2:0:3:0: DEVICE RESET operation started. 2:0:3:0: DEVICE RESET operation timed-out. 2:0:3:0: BUS RESET operation started. 2:0:3:0: BUS RESET operation timed-out. 2:0:3:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 3 lun 0 2:0:4:0: ABORT operation started. 2:0:4:0: ABORT operation timed-out. 2:0:4:0: DEVICE RESET operation started. 2:0:4:0: DEVICE RESET operation timed-out. 2:0:4:0: BUS RESET operation started. 2:0:4:0: BUS RESET operation timed-out. 2:0:4:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 4 lun 0 2:0:5:0: ABORT operation started. 2:0:5:0: ABORT operation timed-out. 2:0:5:0: DEVICE RESET operation started. 2:0:5:0: DEVICE RESET operation timed-out. 2:0:5:0: BUS RESET operation started. 2:0:5:0: BUS RESET operation timed-out. 2:0:5:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 5 lun 0 2:0:6:0: ABORT operation started. 2:0:6:0: ABORT operation timed-out. 2:0:6:0: DEVICE RESET operation started. 2:0:6:0: DEVICE RESET operation timed-out. 2:0:6:0: BUS RESET operation started. 2:0:6:0: BUS RESET operation timed-out. 2:0:6:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 6 lun 0 2:0:8:0: ABORT operation started. 2:0:8:0: ABORT operation timed-out. 2:0:8:0: DEVICE RESET operation started. 2:0:8:0: DEVICE RESET operation timed-out. 2:0:8:0: BUS RESET operation started. 2:0:8:0: BUS RESET operation timed-out. 2:0:8:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 8 lun 0 2:0:9:0: ABORT operation started. 2:0:9:0: ABORT operation timed-out. 2:0:9:0: DEVICE RESET operation started. 2:0:9:0: DEVICE RESET operation timed-out. 2:0:9:0: BUS RESET operation started. 2:0:9:0: BUS RESET operation timed-out. 2:0:9:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 9 lun 0 2:0:10:0: ABORT operation started. 2:0:10:0: ABORT operation timed-out. 2:0:10:0: DEVICE RESET operation started. 2:0:10:0: DEVICE RESET operation timed-out. 2:0:10:0: BUS RESET operation started. 2:0:10:0: BUS RESET operation timed-out. 2:0:10:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 10 lun 0 2:0:11:0: ABORT operation started. 2:0:11:0: ABORT operation timed-out. 2:0:11:0: DEVICE RESET operation started. 2:0:11:0: DEVICE RESET operation timed-out. 2:0:11:0: BUS RESET operation started. 2:0:11:0: BUS RESET operation timed-out. 2:0:11:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 11 lun 0 2:0:12:0: ABORT operation started. 2:0:12:0: ABORT operation timed-out. 2:0:12:0: DEVICE RESET operation started. 2:0:12:0: DEVICE RESET operation timed-out. 2:0:12:0: BUS RESET operation started. 2:0:12:0: BUS RESET operation timed-out. 2:0:12:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 12 lun 0 2:0:13:0: ABORT operation started. 2:0:13:0: ABORT operation timed-out. 2:0:13:0: DEVICE RESET operation started. 2:0:13:0: DEVICE RESET operation timed-out. 2:0:13:0: BUS RESET operation started. 2:0:13:0: BUS RESET operation timed-out. 2:0:13:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 13 lun 0 2:0:14:0: ABORT operation started. 2:0:14:0: ABORT operation timed-out. 2:0:14:0: DEVICE RESET operation started. 2:0:14:0: DEVICE RESET operation timed-out. 2:0:14:0: BUS RESET operation started. 2:0:14:0: BUS RESET operation timed-out. 2:0:14:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 14 lun 0 2:0:15:0: ABORT operation started. 2:0:15:0: ABORT operation timed-out. 2:0:15:0: DEVICE RESET operation started. 2:0:15:0: DEVICE RESET operation timed-out. 2:0:15:0: BUS RESET operation started. 2:0:15:0: BUS RESET operation timed-out. 2:0:15:0: HOST RESET operation started. sym2: SCSI BUS has been reset. 2:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 2 channel 0 id 15 lun 0 sym3: <825a> rev 0x13 at pci 0001:10:0e.0 irq 41 sym3: No NVRAM, ID 7, Fast-10, SE, parity checking sym3: SCSI BUS has been reset. scsi3 : sym-2.2.0 3:0:0:0: ABORT operation started. 3:0:0:0: ABORT operation timed-out. 3:0:0:0: DEVICE RESET operation started. 3:0:0:0: DEVICE RESET operation timed-out. 3:0:0:0: BUS RESET operation started. 3:0:0:0: BUS RESET operation timed-out. 3:0:0:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 0 lun 0 3:0:1:0: ABORT operation started. 3:0:1:0: ABORT operation timed-out. 3:0:1:0: DEVICE RESET operation started. 3:0:1:0: DEVICE RESET operation timed-out. 3:0:1:0: BUS RESET operation started. 3:0:1:0: BUS RESET operation timed-out. 3:0:1:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 1 lun 0 3:0:2:0: ABORT operation started. 3:0:2:0: ABORT operation timed-out. 3:0:2:0: DEVICE RESET operation started. 3:0:2:0: DEVICE RESET operation timed-out. 3:0:2:0: BUS RESET operation started. 3:0:2:0: BUS RESET operation timed-out. 3:0:2:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 2 lun 0 3:0:3:0: ABORT operation started. 3:0:3:0: ABORT operation timed-out. 3:0:3:0: DEVICE RESET operation started. 3:0:3:0: DEVICE RESET operation timed-out. 3:0:3:0: BUS RESET operation started. 3:0:3:0: BUS RESET operation timed-out. 3:0:3:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 3 lun 0 3:0:4:0: ABORT operation started. 3:0:4:0: ABORT operation timed-out. 3:0:4:0: DEVICE RESET operation started. 3:0:4:0: DEVICE RESET operation timed-out. 3:0:4:0: BUS RESET operation started. 3:0:4:0: BUS RESET operation timed-out. 3:0:4:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 4 lun 0 3:0:5:0: ABORT operation started. 3:0:5:0: ABORT operation timed-out. 3:0:5:0: DEVICE RESET operation started. 3:0:5:0: DEVICE RESET operation timed-out. 3:0:5:0: BUS RESET operation started. 3:0:5:0: BUS RESET operation timed-out. 3:0:5:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 5 lun 0 3:0:6:0: ABORT operation started. 3:0:6:0: ABORT operation timed-out. 3:0:6:0: DEVICE RESET operation started. 3:0:6:0: DEVICE RESET operation timed-out. 3:0:6:0: BUS RESET operation started. 3:0:6:0: BUS RESET operation timed-out. 3:0:6:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 6 lun 0 3:0:8:0: ABORT operation started. 3:0:8:0: ABORT operation timed-out. 3:0:8:0: DEVICE RESET operation started. 3:0:8:0: DEVICE RESET operation timed-out. 3:0:8:0: BUS RESET operation started. 3:0:8:0: BUS RESET operation timed-out. 3:0:8:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 8 lun 0 3:0:9:0: ABORT operation started. 3:0:9:0: ABORT operation timed-out. 3:0:9:0: DEVICE RESET operation started. 3:0:9:0: DEVICE RESET operation timed-out. 3:0:9:0: BUS RESET operation started. 3:0:9:0: BUS RESET operation timed-out. 3:0:9:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 9 lun 0 3:0:10:0: ABORT operation started. 3:0:10:0: ABORT operation timed-out. 3:0:10:0: DEVICE RESET operation started. 3:0:10:0: DEVICE RESET operation timed-out. 3:0:10:0: BUS RESET operation started. 3:0:10:0: BUS RESET operation timed-out. 3:0:10:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 10 lun 0 3:0:11:0: ABORT operation started. 3:0:11:0: ABORT operation timed-out. 3:0:11:0: DEVICE RESET operation started. 3:0:11:0: DEVICE RESET operation timed-out. 3:0:11:0: BUS RESET operation started. 3:0:11:0: BUS RESET operation timed-out. 3:0:11:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 11 lun 0 3:0:12:0: ABORT operation started. 3:0:12:0: ABORT operation timed-out. 3:0:12:0: DEVICE RESET operation started. 3:0:12:0: DEVICE RESET operation timed-out. 3:0:12:0: BUS RESET operation started. 3:0:12:0: BUS RESET operation timed-out. 3:0:12:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 12 lun 0 3:0:13:0: ABORT operation started. 3:0:13:0: ABORT operation timed-out. 3:0:13:0: DEVICE RESET operation started. 3:0:13:0: DEVICE RESET operation timed-out. 3:0:13:0: BUS RESET operation started. 3:0:13:0: BUS RESET operation timed-out. 3:0:13:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 13 lun 0 3:0:14:0: ABORT operation started. 3:0:14:0: ABORT operation timed-out. 3:0:14:0: DEVICE RESET operation started. 3:0:14:0: DEVICE RESET operation timed-out. 3:0:14:0: BUS RESET operation started. 3:0:14:0: BUS RESET operation timed-out. 3:0:14:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 14 lun 0 3:0:15:0: ABORT operation started. 3:0:15:0: ABORT operation timed-out. 3:0:15:0: DEVICE RESET operation started. 3:0:15:0: DEVICE RESET operation timed-out. 3:0:15:0: BUS RESET operation started. 3:0:15:0: BUS RESET operation timed-out. 3:0:15:0: HOST RESET operation started. sym3: SCSI BUS has been reset. 3:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 3 channel 0 id 15 lun 0 sym4: <825a> rev 0x13 at pci 0002:20:0b.0 irq 51 sym4: No NVRAM, ID 7, Fast-10, SE, parity checking sym4: SCSI BUS has been reset. scsi4 : sym-2.2.0 4:0:0:0: ABORT operation started. 4:0:0:0: ABORT operation timed-out. 4:0:0:0: DEVICE RESET operation started. 4:0:0:0: DEVICE RESET operation timed-out. 4:0:0:0: BUS RESET operation started. 4:0:0:0: BUS RESET operation timed-out. 4:0:0:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 0 lun 0 4:0:1:0: ABORT operation started. 4:0:1:0: ABORT operation timed-out. 4:0:1:0: DEVICE RESET operation started. 4:0:1:0: DEVICE RESET operation timed-out. 4:0:1:0: BUS RESET operation started. 4:0:1:0: BUS RESET operation timed-out. 4:0:1:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 1 lun 0 4:0:2:0: ABORT operation started. 4:0:2:0: ABORT operation timed-out. 4:0:2:0: DEVICE RESET operation started. 4:0:2:0: DEVICE RESET operation timed-out. 4:0:2:0: BUS RESET operation started. 4:0:2:0: BUS RESET operation timed-out. 4:0:2:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 2 lun 0 4:0:3:0: ABORT operation started. 4:0:3:0: ABORT operation timed-out. 4:0:3:0: DEVICE RESET operation started. 4:0:3:0: DEVICE RESET operation timed-out. 4:0:3:0: BUS RESET operation started. 4:0:3:0: BUS RESET operation timed-out. 4:0:3:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 3 lun 0 4:0:4:0: ABORT operation started. 4:0:4:0: ABORT operation timed-out. 4:0:4:0: DEVICE RESET operation started. 4:0:4:0: DEVICE RESET operation timed-out. 4:0:4:0: BUS RESET operation started. 4:0:4:0: BUS RESET operation timed-out. 4:0:4:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 4 lun 0 4:0:5:0: ABORT operation started. 4:0:5:0: ABORT operation timed-out. 4:0:5:0: DEVICE RESET operation started. 4:0:5:0: DEVICE RESET operation timed-out. 4:0:5:0: BUS RESET operation started. 4:0:5:0: BUS RESET operation timed-out. 4:0:5:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 5 lun 0 4:0:6:0: ABORT operation started. 4:0:6:0: ABORT operation timed-out. 4:0:6:0: DEVICE RESET operation started. 4:0:6:0: DEVICE RESET operation timed-out. 4:0:6:0: BUS RESET operation started. 4:0:6:0: BUS RESET operation timed-out. 4:0:6:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 6 lun 0 4:0:8:0: ABORT operation started. 4:0:8:0: ABORT operation timed-out. 4:0:8:0: DEVICE RESET operation started. 4:0:8:0: DEVICE RESET operation timed-out. 4:0:8:0: BUS RESET operation started. 4:0:8:0: BUS RESET operation timed-out. 4:0:8:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 8 lun 0 4:0:9:0: ABORT operation started. 4:0:9:0: ABORT operation timed-out. 4:0:9:0: DEVICE RESET operation started. 4:0:9:0: DEVICE RESET operation timed-out. 4:0:9:0: BUS RESET operation started. 4:0:9:0: BUS RESET operation timed-out. 4:0:9:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 9 lun 0 4:0:10:0: ABORT operation started. 4:0:10:0: ABORT operation timed-out. 4:0:10:0: DEVICE RESET operation started. 4:0:10:0: DEVICE RESET operation timed-out. 4:0:10:0: BUS RESET operation started. 4:0:10:0: BUS RESET operation timed-out. 4:0:10:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 10 lun 0 4:0:11:0: ABORT operation started. 4:0:11:0: ABORT operation timed-out. 4:0:11:0: DEVICE RESET operation started. 4:0:11:0: DEVICE RESET operation timed-out. 4:0:11:0: BUS RESET operation started. 4:0:11:0: BUS RESET operation timed-out. 4:0:11:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 11 lun 0 4:0:12:0: ABORT operation started. 4:0:12:0: ABORT operation timed-out. 4:0:12:0: DEVICE RESET operation started. 4:0:12:0: DEVICE RESET operation timed-out. 4:0:12:0: BUS RESET operation started. 4:0:12:0: BUS RESET operation timed-out. 4:0:12:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 12 lun 0 4:0:13:0: ABORT operation started. 4:0:13:0: ABORT operation timed-out. 4:0:13:0: DEVICE RESET operation started. 4:0:13:0: DEVICE RESET operation timed-out. 4:0:13:0: BUS RESET operation started. 4:0:13:0: BUS RESET operation timed-out. 4:0:13:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 13 lun 0 4:0:14:0: ABORT operation started. 4:0:14:0: ABORT operation timed-out. 4:0:14:0: DEVICE RESET operation started. 4:0:14:0: DEVICE RESET operation timed-out. 4:0:14:0: BUS RESET operation started. 4:0:14:0: BUS RESET operation timed-out. 4:0:14:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 14 lun 0 4:0:15:0: ABORT operation started. 4:0:15:0: ABORT operation timed-out. 4:0:15:0: DEVICE RESET operation started. 4:0:15:0: DEVICE RESET operation timed-out. 4:0:15:0: BUS RESET operation started. 4:0:15:0: BUS RESET operation timed-out. 4:0:15:0: HOST RESET operation started. sym4: SCSI BUS has been reset. 4:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 4 channel 0 id 15 lun 0 sym5: <875> rev 0x3 at pci 0002:20:0d.0 irq 55 sym5: No NVRAM, ID 7, Fast-20, SE, parity checking sym5: SCSI BUS has been reset. scsi5 : sym-2.2.0 5:0:0:0: ABORT operation started. 5:0:0:0: ABORT operation timed-out. 5:0:0:0: DEVICE RESET operation started. 5:0:0:0: DEVICE RESET operation timed-out. 5:0:0:0: BUS RESET operation started. 5:0:0:0: BUS RESET operation timed-out. 5:0:0:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:0:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 0 lun 0 5:0:1:0: ABORT operation started. 5:0:1:0: ABORT operation timed-out. 5:0:1:0: DEVICE RESET operation started. 5:0:1:0: DEVICE RESET operation timed-out. 5:0:1:0: BUS RESET operation started. 5:0:1:0: BUS RESET operation timed-out. 5:0:1:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:1:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 1 lun 0 5:0:2:0: ABORT operation started. 5:0:2:0: ABORT operation timed-out. 5:0:2:0: DEVICE RESET operation started. 5:0:2:0: DEVICE RESET operation timed-out. 5:0:2:0: BUS RESET operation started. 5:0:2:0: BUS RESET operation timed-out. 5:0:2:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:2:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 2 lun 0 5:0:3:0: ABORT operation started. 5:0:3:0: ABORT operation timed-out. 5:0:3:0: DEVICE RESET operation started. 5:0:3:0: DEVICE RESET operation timed-out. 5:0:3:0: BUS RESET operation started. 5:0:3:0: BUS RESET operation timed-out. 5:0:3:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:3:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 3 lun 0 5:0:4:0: ABORT operation started. 5:0:4:0: ABORT operation timed-out. 5:0:4:0: DEVICE RESET operation started. 5:0:4:0: DEVICE RESET operation timed-out. 5:0:4:0: BUS RESET operation started. 5:0:4:0: BUS RESET operation timed-out. 5:0:4:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:4:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 4 lun 0 5:0:5:0: ABORT operation started. 5:0:5:0: ABORT operation timed-out. 5:0:5:0: DEVICE RESET operation started. 5:0:5:0: DEVICE RESET operation timed-out. 5:0:5:0: BUS RESET operation started. 5:0:5:0: BUS RESET operation timed-out. 5:0:5:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:5:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 5 lun 0 5:0:6:0: ABORT operation started. 5:0:6:0: ABORT operation timed-out. 5:0:6:0: DEVICE RESET operation started. 5:0:6:0: DEVICE RESET operation timed-out. 5:0:6:0: BUS RESET operation started. 5:0:6:0: BUS RESET operation timed-out. 5:0:6:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:6:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 6 lun 0 5:0:8:0: ABORT operation started. 5:0:8:0: ABORT operation timed-out. 5:0:8:0: DEVICE RESET operation started. 5:0:8:0: DEVICE RESET operation timed-out. 5:0:8:0: BUS RESET operation started. 5:0:8:0: BUS RESET operation timed-out. 5:0:8:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:8:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 8 lun 0 5:0:9:0: ABORT operation started. 5:0:9:0: ABORT operation timed-out. 5:0:9:0: DEVICE RESET operation started. 5:0:9:0: DEVICE RESET operation timed-out. 5:0:9:0: BUS RESET operation started. 5:0:9:0: BUS RESET operation timed-out. 5:0:9:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:9:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 9 lun 0 5:0:10:0: ABORT operation started. 5:0:10:0: ABORT operation timed-out. 5:0:10:0: DEVICE RESET operation started. 5:0:10:0: DEVICE RESET operation timed-out. 5:0:10:0: BUS RESET operation started. 5:0:10:0: BUS RESET operation timed-out. 5:0:10:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:10:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 10 lun 0 5:0:11:0: ABORT operation started. 5:0:11:0: ABORT operation timed-out. 5:0:11:0: DEVICE RESET operation started. 5:0:11:0: DEVICE RESET operation timed-out. 5:0:11:0: BUS RESET operation started. 5:0:11:0: BUS RESET operation timed-out. 5:0:11:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:11:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 11 lun 0 5:0:12:0: ABORT operation started. 5:0:12:0: ABORT operation timed-out. 5:0:12:0: DEVICE RESET operation started. 5:0:12:0: DEVICE RESET operation timed-out. 5:0:12:0: BUS RESET operation started. 5:0:12:0: BUS RESET operation timed-out. 5:0:12:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:12:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 12 lun 0 5:0:13:0: ABORT operation started. 5:0:13:0: ABORT operation timed-out. 5:0:13:0: DEVICE RESET operation started. 5:0:13:0: DEVICE RESET operation timed-out. 5:0:13:0: BUS RESET operation started. 5:0:13:0: BUS RESET operation timed-out. 5:0:13:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:13:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 13 lun 0 5:0:14:0: ABORT operation started. 5:0:14:0: ABORT operation timed-out. 5:0:14:0: DEVICE RESET operation started. 5:0:14:0: DEVICE RESET operation timed-out. 5:0:14:0: BUS RESET operation started. 5:0:14:0: BUS RESET operation timed-out. 5:0:14:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:14:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 14 lun 0 5:0:15:0: ABORT operation started. 5:0:15:0: ABORT operation timed-out. 5:0:15:0: DEVICE RESET operation started. 5:0:15:0: DEVICE RESET operation timed-out. 5:0:15:0: BUS RESET operation started. 5:0:15:0: BUS RESET operation timed-out. 5:0:15:0: HOST RESET operation started. sym5: SCSI BUS has been reset. 5:0:15:0: HOST RESET operation timed-out. scsi: Device offlined - not ready after error recovery: host 5 channel 0 id 15 lun 0 ipr: IBM Power RAID SCSI Device Driver version: 2.0.13 (February 21, 2005) st: Version 20050312, fixed bufsize 32768, s/g segs 256 Initializing USB Mass Storage driver... usbcore: registered new driver usb-storage USB Mass Storage support registered. usbcore: registered new driver hiddev usbcore: registered new driver usbhid drivers/usb/input/hid-core.c: v2.01:USB HID core driver mice: PS/2 mouse device common for all mice md: linear personality registered as nr 1 md: raid0 personality registered as nr 2 md: raid1 personality registered as nr 3 md: raid5 personality registered as nr 4 raid5: measuring checksumming speed 8regs : 428.000 MB/sec 8regs_prefetch: 388.000 MB/sec 32regs : 552.000 MB/sec 32regs_prefetch: 472.000 MB/sec raid5: using function: 32regs (552.000 MB/sec) md: md driver 0.90.1 MAX_MD_DEVS=256, MD_SB_DISKS=27 device-mapper: 4.4.0-ioctl (2005-01-12) initialised: dm-devel at redhat.com oprofile: using ppc64/rs64 performance monitoring. NET: Registered protocol family 2 atkbd.c: keyboard reset failed on isa0060/serio1 IP: routing cache hash table of 65536 buckets, 512Kbytes TCP established hash table entries: 524288 (order: 10, 4194304 bytes) TCP bind hash table entries: 65536 (order: 7, 524288 bytes) TCP: Hash tables configured (established 524288 bind 65536) IPv4 over IPv4 tunneling driver NET: Registered protocol family 1 NET: Registered protocol family 17 md: Autodetecting RAID arrays. md: autorun ... md: ... autorun DONE. VFS: Insert root floppy and press ENTER From moilanen at austin.ibm.com Wed Jun 1 07:55:07 2005 From: moilanen at austin.ibm.com (Jake Moilanen) Date: Tue, 31 May 2005 16:55:07 -0500 Subject: [PATCH] PCI device-node failure detection In-Reply-To: <20050531195127.GD3723@otto> References: <20050531101225.510efbf7.moilanen@austin.ibm.com> <20050531195127.GD3723@otto> Message-ID: <20050531165507.44dba54a.moilanen@austin.ibm.com> > "fail" is not the only possible state that would indicate that the > device is unusable, if I'm reading IEEE 1275 right. There is also > "disabled" and "fail-xxx" where xxx is additional info about the > fault. I've never seen "fail-xxx" myself but I've seen "disabled" on > devices that were deconfigured by firmware (failing cpu iirc). I haven't seen this on an adapter, but better to follow the spec. > Unless we want to treat "disabled" and "fail[-xxx]" differently, I > think we should be checking that the status property, if present, > says "okay". > > Something like: > > int dn_failed(struct device_node *dn) > { > char *status = get_property(dn, "status", NULL); > > if (!status) > return 0; > > if (!strcmp(status, "okay")) > return 0; > > return 1; > } I like that much more. > Also, I think this function could be made a static helper in > pSeries_pci.c until something outside of that file needs it. Hmm...I thought we were trying to keep all device-tree specific items in prom.c. Here's a fixed up version of the dn_failed(). Signed-off-by: Jake Moilanen Index: 2.6.12/arch/ppc64/kernel/prom.c =================================================================== --- 2.6.12.orig/arch/ppc64/kernel/prom.c 2005-03-02 01:38:13.000000000 -0600 +++ 2.6.12/arch/ppc64/kernel/prom.c 2005-05-31 21:05:58.674114874 -0500 @@ -1887,6 +1887,22 @@ *next = prop; } +int +dn_failed(struct device_node * dn) +{ + char * status; + + status = get_property(dn, "status", NULL); + + if (!status) + return 0; + + if (!strcmp(status, "okay")) + return 0; + + return 1; +} + #if 0 void print_properties(struct device_node *np) Index: 2.6.12/arch/ppc64/kernel/pSeries_pci.c =================================================================== --- 2.6.12.orig/arch/ppc64/kernel/pSeries_pci.c 2005-03-02 01:38:34.000000000 -0600 +++ 2.6.12/arch/ppc64/kernel/pSeries_pci.c 2005-05-27 18:44:33.000000000 -0500 @@ -96,7 +96,7 @@ /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn) + if (dn->devfn == devfn && !dn_failed(dn)) return rtas_read_config(dn, where, size, val); return PCIBIOS_DEVICE_NOT_FOUND; } @@ -138,7 +138,7 @@ /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn) + if (dn->devfn == devfn && !dn_failed(dn)) return rtas_write_config(dn, where, size, val); return PCIBIOS_DEVICE_NOT_FOUND; } Index: 2.6.12/include/asm-ppc64/prom.h =================================================================== --- 2.6.12.orig/include/asm-ppc64/prom.h 2005-03-02 01:38:33.000000000 -0600 +++ 2.6.12/include/asm-ppc64/prom.h 2005-05-27 18:44:33.000000000 -0500 @@ -225,5 +225,6 @@ extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); extern void prom_add_property(struct device_node* np, struct property* prop); +extern int dn_failed(struct device_node * dn); #endif /* _PPC64_PROM_H */ From linas at austin.ibm.com Wed Jun 1 07:56:28 2005 From: linas at austin.ibm.com (Linas Vepstas) Date: Tue, 31 May 2005 16:56:28 -0500 Subject: [PATCH]: PCI Error Recovery Implementation In-Reply-To: <1117572727.7775.11.camel@sinatra.austin.ibm.com> References: <20050531203028.GD31199@austin.ibm.com> <1117572727.7775.11.camel@sinatra.austin.ibm.com> Message-ID: <20050531215628.GE31199@austin.ibm.com> On Tue, May 31, 2005 at 03:52:07PM -0500, John Rose was heard to remark: > Hi Linas/Greg/Everyone- > > +int handle_eeh_events (struct notifier_block *self, > + unsigned long reason, void *ev) > > At the risk of sounding like a broken record, I don't think that this > belongs in the RPA PCI Hotplug driver. This bit of code _uses_ PCI > Hotplug rather than implementing it, and thus stands out from the rest > of the module. Not to mention that it uses EEH-specific stuff that > doesn't belong here. I'm in the midst of reducing the codebase of this > module significantly, and this adds more unrelated stuff to an already > cluttered module. > > I think the PCI hotplug driver could register enable/disable functions > with eeh.c, and that the handle_events() code should reside there. If > someone has a good technical explanation of why this is bad, please > chime in. What would be the correct way of forcing the rpaphp.o module to get loaded, and what would be the correct way of invoking functions in that module? --linas From johnrose at austin.ibm.com Wed Jun 1 08:13:11 2005 From: johnrose at austin.ibm.com (John Rose) Date: Tue, 31 May 2005 17:13:11 -0500 Subject: [PATCH]: PCI Error Recovery Implementation In-Reply-To: <20050531215628.GE31199@austin.ibm.com> References: <20050531203028.GD31199@austin.ibm.com> <1117572727.7775.11.camel@sinatra.austin.ibm.com> <20050531215628.GE31199@austin.ibm.com> Message-ID: <1117577591.7775.30.camel@sinatra.austin.ibm.com> Hi Linas- > What would be the correct way of forcing the rpaphp.o module to get > loaded, The burden is on the distro/user to either compile-in or load the PCI Hotplug module. This is the case with or without your patch, and regardless of the ultimate solution to the EEH problem. > and what would be the correct way of invoking functions in that > module? Arch/ppc64/kernel/eeh.c could have function pointers for enable/disable slot. Something like: int (*hp_disable_slot)(struct pci_bus *bus) = NULL; int (*hp_enable_slot)(struct pci_bus *bus) = NULL; These could either be exported, or be static and accompanied by small accessor functions. The RPA hotplug module could set these pointers at module init, either directly or through accessors. If these aren't set at runtime, the module isn't loaded. This puts the eeh footprint on rpaphp at 4 lines, and leaves the EEH implementation in an eeh file. Thoughts? John From paulus at samba.org Wed Jun 1 08:19:00 2005 From: paulus at samba.org (Paul Mackerras) Date: Wed, 1 Jun 2005 08:19:00 +1000 Subject: [PATCH] correct printing to op panel In-Reply-To: <429CDC42.30905@austin.ibm.com> References: <429CDC42.30905@austin.ibm.com> Message-ID: <17052.58068.511994.89604@cargo.ozlabs.ibm.com> Mike Strosaker writes: > This patch corrects the printing of progress indicators to the op panel on > ppc64 systems. Each discrete reference code should begin with a form feed > char to clear the op panel, and the first and second lines should be separated > with a CR/LF sequence. Padding with spaces is not necessary. I want to think about this one a bit more. The ppc_md.progress() calls aren't only used for the i/pSeries op panels, and I need to think about the effect of \f on the other progress implementations. It would be best, I think, if the outputting of \f could be done by the pSeries progress function rather than the caller, if possible. Paul. From linas at austin.ibm.com Wed Jun 1 08:38:01 2005 From: linas at austin.ibm.com (Linas Vepstas) Date: Tue, 31 May 2005 17:38:01 -0500 Subject: [PATCH]: PCI Error Recovery Implementation In-Reply-To: <1117577591.7775.30.camel@sinatra.austin.ibm.com> References: <20050531203028.GD31199@austin.ibm.com> <1117572727.7775.11.camel@sinatra.austin.ibm.com> <20050531215628.GE31199@austin.ibm.com> <1117577591.7775.30.camel@sinatra.austin.ibm.com> Message-ID: <20050531223801.GF31199@austin.ibm.com> On Tue, May 31, 2005 at 05:13:11PM -0500, John Rose was heard to remark: > > and what would be the correct way of invoking functions in that > > module? > > Arch/ppc64/kernel/eeh.c could have function pointers for enable/disable > slot. Something like: > int (*hp_disable_slot)(struct pci_bus *bus) = NULL; > int (*hp_enable_slot)(struct pci_bus *bus) = NULL; > > These could either be exported, or be static and accompanied by small > accessor functions. The RPA hotplug module could set these pointers at > module init, either directly or through accessors. If these aren't set > at runtime, the module isn't loaded. > > This puts the eeh footprint on rpaphp at 4 lines, and leaves the EEH > implementation in an eeh file. That was the original implementation about a year ago. Lengthly discussion on the mailing lists suggested that this was the wrong way to do it. I'm not sure, but I vaguely remember Paul Mackerras as being (one of) the drivers urging the current implementation. Paul, could you please comment on this issue? Personally, I don't much care; either mechanism has the same net result. --linas From paulus at samba.org Wed Jun 1 09:05:04 2005 From: paulus at samba.org (Paul Mackerras) Date: Wed, 1 Jun 2005 09:05:04 +1000 Subject: book e idea In-Reply-To: <429C5648.2040501@blach.dnsalias.org> References: <429C5648.2040501@blach.dnsalias.org> Message-ID: <17052.60832.525453.668005@cargo.ozlabs.ibm.com> Ralph Blach writes: > could the OS be run in translation state 0, and and the users in > translation state 1? Yes, it is possible. The main problem that it would introduce is that copy_to_user, copy_from_user, put_user, get_user etc. would no longer be able to access user space directly but would instead have to set up page mappings, and would therefore become bigger and slower. > The advantage to this would be is that user task could have true 4 gb > addressing on a and so could the kernel. Yes. There doesn't seem to be a lot of pressure for giving userspace more than 2GB in the embedded world though. Paul. From strosake at austin.ibm.com Wed Jun 1 07:50:58 2005 From: strosake at austin.ibm.com (Mike Strosaker) Date: Tue, 31 May 2005 16:50:58 -0500 Subject: [PATCH] correct printing to op panel Message-ID: <429CDC42.30905@austin.ibm.com> This patch corrects the printing of progress indicators to the op panel on ppc64 systems. Each discrete reference code should begin with a form feed char to clear the op panel, and the first and second lines should be separated with a CR/LF sequence. Padding with spaces is not necessary. Also, capitalize the hex value printed on the first line, to be consistent with the values printed by firmware, service processor, etc. Signed-off-by: Mike Strosaker diff -Nru linux-2.6.12-rc5.orig/arch/ppc64/kernel/pSeries_setup.c linux-2.6.12-rc5/arch/ppc64/kernel/pSeries_setup.c --- linux-2.6.12-rc5.orig/arch/ppc64/kernel/pSeries_setup.c 2005-05-31 15:35:37.000000000 -0500 +++ linux-2.6.12-rc5/arch/ppc64/kernel/pSeries_setup.c 2005-05-31 15:16:49.000000000 -0500 @@ -240,7 +240,7 @@ static int __init pSeries_init_panel(void) { /* Manually leave the kernel version on the panel. */ - ppc_md.progress("Linux ppc64\n", 0); + ppc_md.progress("\fLinux ppc64\r\n", 0); ppc_md.progress(UTS_RELEASE, 0); return 0; diff -Nru linux-2.6.12-rc5.orig/arch/ppc64/kernel/setup.c linux-2.6.12-rc5/arch/ppc64/kernel/setup.c --- linux-2.6.12-rc5.orig/arch/ppc64/kernel/setup.c 2005-05-31 15:35:37.000000000 -0500 +++ linux-2.6.12-rc5/arch/ppc64/kernel/setup.c 2005-05-31 15:17:10.000000000 -0500 @@ -1085,9 +1085,9 @@ if (ppc_md.progress) { char buf[32]; - sprintf(buf, "%08x \n", src); + sprintf(buf, "\f%08X\r\n", src); ppc_md.progress(buf, 0); - sprintf(buf, "%-16s", msg); + snprintf(buf, 32, "%s", msg); ppc_md.progress(buf, 0); } } From benh at kernel.crashing.org Wed Jun 1 09:34:46 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 09:34:46 +1000 Subject: [PATCH] PCI device-node failure detection In-Reply-To: <20050531101225.510efbf7.moilanen@austin.ibm.com> References: <20050531101225.510efbf7.moilanen@austin.ibm.com> Message-ID: <1117582486.5826.62.camel@gaston> On Tue, 2005-05-31 at 10:12 -0500, Jake Moilanen wrote: > OpenFirmware marks devices as failed in the device-tree when a hardware > problem is detected. The kernel needs to fail config reads/writes to > prevent a kernel crash when incorrect data is read. > > This patch validates that the device-node is not marked "fail" when > config space reads/writes are attempted. > > Signed-off-by: Jake Moilanen > > Index: 2.6.12/arch/ppc64/kernel/prom.c > =================================================================== > --- 2.6.12.orig/arch/ppc64/kernel/prom.c 2005-03-02 01:38:13.000000000 -0600 > +++ 2.6.12/arch/ppc64/kernel/prom.c 2005-05-27 18:44:33.172559207 -0500 > @@ -1887,6 +1887,19 @@ > *next = prop; > } > > +int > +dn_failed(struct device_node * dn) > +{ > + char * status; > + > + status = get_property(dn, "status", NULL); > + > + if (status && !strcmp(status, "fail")) > + return 1; > + > + return 0; > +} > + Please, keep that out of prom.c (and I don't like the function name :) Ben. From benh at kernel.crashing.org Wed Jun 1 09:37:55 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 09:37:55 +1000 Subject: [PATCH] PCI device-node failure detection In-Reply-To: <20050531165507.44dba54a.moilanen@austin.ibm.com> References: <20050531101225.510efbf7.moilanen@austin.ibm.com> <20050531195127.GD3723@otto> <20050531165507.44dba54a.moilanen@austin.ibm.com> Message-ID: <1117582676.5826.66.camel@gaston> > Hmm...I thought we were trying to keep all device-tree specific items in > prom.c. Not really. In fact, I want only "generic" device-tree stuff in there, and that isn't quite it. I'm about to remove the bunch of interpret_xxxx_props() for example, ultimately, I want prom.c to only contain the structure accessors, flatten/unflatten code, etc.. Besides, if you really want to export it, considering that it's "standard" enough to be in generic code, then it should be rather called something like. int of_device_failed(...) And finally, i'd rather have it backward, that is something like of_device_available(). Ben. From benh at kernel.crashing.org Wed Jun 1 14:54:25 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 14:54:25 +1000 Subject: [PATCH] ppc64: Fix a device-tree bug on Apple's Message-ID: <1117601666.5826.85.camel@gaston> Hi ! Apple's Open Firmware has a funny bug when creating the /cpus nodes where it leaves a dangling '\0' character in the CPU name which ends up appearing in the full path of the node. This is bogus and confuses /proc/device-tree badly. This patch strips those bogus zero's from the node full path when reading the device-tree from Open Firmware. The "name" property is not modified and still contains the spurrious 0 (it basically contains 0 tailing 0 instead of one) but that shouldn't be a problem. An equivalent patch for ppc32 will follow shortly Signed-off-by: Benjamin Herrenschmidt Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-01 14:38:21.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-01 14:44:30.000000000 +1000 @@ -1566,7 +1566,7 @@ { int l, align; phandle child; - char *namep, *prev_name, *sstart; + char *namep, *prev_name, *sstart, *p, *ep; unsigned long soff; unsigned char *valp; unsigned long offset = reloc_offset(); @@ -1588,6 +1588,14 @@ call_prom("package-to-path", 3, 1, node, namep, l); } namep[l] = '\0'; + /* Fixup an Apple bug where they have bogus \0 chars in the + * middle of the path in some properties + */ + for (p = namep, ep = namep + l; p < ep; p++) + if (*p == '\0') { + memmove(p, p+1, ep - p); + ep--; l--; + } *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); } From benh at kernel.crashing.org Wed Jun 1 17:07:27 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 17:07:27 +1000 Subject: [PATCH] ppc32/ppc64: cleanup /proc/device-tree Message-ID: <1117609647.5409.8.camel@gaston> Hi ! This patch cleans up the /proc/device-tree representation of the Open Firmware device-tree on ppc and ppc64. It does the following things: - Workaround an issue in some Apple device-trees where a property may exist with the same name as a child node of the parent. We now simply "drop" the property instead of creating duplicate entries in /proc with random result... - Do not try to chop off the "@0" at the end of a node name whose unit address is 0. This is not useful, inconsistent, and the code was buggy and didn't always work anyway. - Do not create symlinks for the short name and unit address parts of a ndoe. These were never really used, bloated the memory footprint of the device-tree with useless struct proc_dir_entry and their matching dentry and inode cache bloat. This results in smaller code, smaller memory footprint, and a more accurate view of the tree presented to userland. Signed-off-by: Benjamin Herrenschmidt Index: linux-work/fs/proc/proc_devtree.c =================================================================== --- linux-work.orig/fs/proc/proc_devtree.c 2005-06-01 16:18:51.000000000 +1000 +++ linux-work/fs/proc/proc_devtree.c 2005-06-01 16:47:35.000000000 +1000 @@ -12,15 +12,8 @@ #include #ifndef HAVE_ARCH_DEVTREE_FIXUPS -static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) -{ -} - -static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de) -{ -} - -static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de) +static inline void set_node_proc_entry(struct device_node *np, + struct proc_dir_entry *de) { } #endif @@ -58,89 +51,67 @@ /* * Process a node, adding entries for its children and its properties. */ -void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de) +void proc_device_tree_add_node(struct device_node *np, + struct proc_dir_entry *de) { struct property *pp; struct proc_dir_entry *ent; - struct device_node *child, *sib; - const char *p, *at; - int l; - struct proc_dir_entry *list, **lastp, *al; + struct device_node *child; + struct proc_dir_entry *list = NULL, **lastp; + const char *p; set_node_proc_entry(np, de); lastp = &list; - for (pp = np->properties; pp != 0; pp = pp->next) { - /* - * Unfortunately proc_register puts each new entry - * at the beginning of the list. So we rearrange them. - */ - ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ? - S_IRUGO : S_IRUSR, de, property_read_proc, pp); - if (ent == 0) - break; - if (!strncmp(pp->name, "security-", 9)) - ent->size = 0; /* don't leak number of password chars */ - else - ent->size = pp->length; - *lastp = ent; - lastp = &ent->next; - } - child = NULL; - while ((child = of_get_next_child(np, child))) { + for (child = NULL; (child = of_get_next_child(np, child));) { p = strrchr(child->full_name, '/'); if (!p) p = child->full_name; else ++p; - /* chop off '@0' if the name ends with that */ - l = strlen(p); - if (l > 2 && p[l-2] == '@' && p[l-1] == '0') - l -= 2; ent = proc_mkdir(p, de); if (ent == 0) break; *lastp = ent; + ent->next = NULL; lastp = &ent->next; proc_device_tree_add_node(child, ent); - - /* - * If we left the address part on the name, consider - * adding symlinks from the name and address parts. - */ - if (p[l] != 0 || (at = strchr(p, '@')) == 0) - continue; - + } + of_node_put(child); + for (pp = np->properties; pp != 0; pp = pp->next) { /* - * If this is the first node with a given name property, - * add a symlink with the name property as its name. + * Yet another Apple device-tree bogosity: on some machines, + * they have properties & nodes with the same name. Those + * properties are quite unimportant for us though, thus we + * simply "skip" them here, but we do have to check. */ - sib = NULL; - while ((sib = of_get_next_child(np, sib)) && sib != child) - if (sib->name && strcmp(sib->name, child->name) == 0) - break; - if (sib == child && strncmp(p, child->name, l) != 0) { - al = proc_symlink(child->name, de, ent->name); - if (al == 0) { - of_node_put(sib); + for (ent = list; ent != NULL; ent = ent->next) + if (!strcmp(ent->name, pp->name)) break; - } - set_node_name_link(child, al); - *lastp = al; - lastp = &al->next; + if (ent != NULL) { + printk(KERN_WARNING "device-tree: property \"%s\" name" + " conflicts with node in %s\n", pp->name, + np->full_name); + continue; } - of_node_put(sib); + /* - * Add another directory with the @address part as its name. + * Unfortunately proc_register puts each new entry + * at the beginning of the list. So we rearrange them. */ - al = proc_symlink(at, de, ent->name); - if (al == 0) + ent = create_proc_read_entry(pp->name, + strncmp(pp->name, "security-", 9) + ? S_IRUGO : S_IRUSR, de, + property_read_proc, pp); + if (ent == 0) break; - set_node_addr_link(child, al); - *lastp = al; - lastp = &al->next; + if (!strncmp(pp->name, "security-", 9)) + ent->size = 0; /* don't leak number of password chars */ + else + ent->size = pp->length; + ent->next = NULL; + *lastp = ent; + lastp = &ent->next; } - of_node_put(child); - *lastp = NULL; de->subdir = list; } Index: linux-work/include/asm-ppc64/prom.h =================================================================== --- linux-work.orig/include/asm-ppc64/prom.h 2005-06-01 16:18:51.000000000 +1000 +++ linux-work/include/asm-ppc64/prom.h 2005-06-01 16:30:30.000000000 +1000 @@ -147,9 +147,7 @@ struct device_node *sibling; struct device_node *next; /* next device of same type */ struct device_node *allnext; /* next in list of all nodes */ - struct proc_dir_entry *pde; /* this node's proc directory */ - struct proc_dir_entry *name_link; /* name symlink */ - struct proc_dir_entry *addr_link; /* addr symlink */ + struct proc_dir_entry *pde; /* this node's proc directory */ struct kref kref; unsigned long _flags; }; @@ -174,15 +172,6 @@ dn->pde = de; } -static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de) -{ - dn->name_link = de; -} - -static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de) -{ - dn->addr_link = de; -} /* OBSOLETE: Old stlye node lookup */ extern struct device_node *find_devices(const char *name); Index: linux-work/arch/ppc64/kernel/pSeries_reconfig.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/pSeries_reconfig.c 2005-06-01 16:18:51.000000000 +1000 +++ linux-work/arch/ppc64/kernel/pSeries_reconfig.c 2005-06-01 16:30:30.000000000 +1000 @@ -47,14 +47,6 @@ remove_proc_entry(pp->name, np->pde); pp = pp->next; } - - /* Assuming that symlinks have the same parent directory as - * np->pde. - */ - if (np->name_link) - remove_proc_entry(np->name_link->name, parent->pde); - if (np->addr_link) - remove_proc_entry(np->addr_link->name, parent->pde); if (np->pde) remove_proc_entry(np->pde->name, parent->pde); } From sfr at canb.auug.org.au Wed Jun 1 18:14:55 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Wed, 1 Jun 2005 18:14:55 +1000 Subject: [PATCH] iSeries: start cleanup of headers Message-ID: <20050601181455.2529c0fd.sfr@canb.auug.org.au> Hi all, I am endeavouring to make the iSeries header files look more "Linux like". This first patch just does white space cleanups, comment cleanups and some simple code reformatting. There are no semantic changes in here. I also remove one header that was only declaring a function that no longer exists. Comments? If none, I will send this to Andrew soon and will base more patches on this beginning. (Yes, that means more StudleyCaps removal :-)) The patch is too large for the list, so you can get it here: http://ozlabs.org/~sfr/iSeries_include.1.diff arch/ppc64/kernel/iSeries_proc.c | 1 arch/ppc64/kernel/iSeries_setup.c | 1 arch/ppc64/kernel/viopath.c | 1 include/asm-ppc64/iSeries/HvCall.h | 100 ++--- include/asm-ppc64/iSeries/HvCallCfg.h | 177 +++------ include/asm-ppc64/iSeries/HvCallEvent.h | 94 +---- include/asm-ppc64/iSeries/HvCallHpt.h | 128 ++---- include/asm-ppc64/iSeries/HvCallPci.h | 486 +++++++++----------------- include/asm-ppc64/iSeries/HvCallSc.h | 38 +- include/asm-ppc64/iSeries/HvCallSm.h | 36 - include/asm-ppc64/iSeries/HvCallXm.h | 114 ++---- include/asm-ppc64/iSeries/HvLpConfig.h | 294 ++++++++------- include/asm-ppc64/iSeries/HvLpEvent.h | 122 +++--- include/asm-ppc64/iSeries/HvReleaseData.h | 76 +--- include/asm-ppc64/iSeries/HvTypes.h | 112 ++--- include/asm-ppc64/iSeries/IoHriMainStore.h | 33 - include/asm-ppc64/iSeries/IoHriProcessorVpd.h | 30 - include/asm-ppc64/iSeries/ItExtVpdPanel.h | 52 +- include/asm-ppc64/iSeries/ItIplParmsReal.h | 97 ++--- include/asm-ppc64/iSeries/ItLpNaca.h | 44 -- include/asm-ppc64/iSeries/ItLpQueue.h | 74 +-- include/asm-ppc64/iSeries/ItLpRegSave.h | 41 +- include/asm-ppc64/iSeries/ItSpCommArea.h | 10 include/asm-ppc64/iSeries/ItVpdAreas.h | 121 +++--- include/asm-ppc64/iSeries/LparData.h | 27 - include/asm-ppc64/iSeries/LparMap.h | 42 +- include/asm-ppc64/iSeries/XmPciLpEvent.h | 15 include/asm-ppc64/iSeries/iSeries_io.h | 59 +-- include/asm-ppc64/iSeries/iSeries_irq.h | 18 include/asm-ppc64/iSeries/iSeries_pci.h | 161 ++++---- include/asm-ppc64/iSeries/iSeries_proc.h | 24 - include/asm-ppc64/iSeries/mf.h | 5 include/asm-ppc64/iSeries/vio.h | 57 +-- 33 files changed, 1153 insertions(+), 1537 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ From benh at kernel.crashing.org Wed Jun 1 18:26:30 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 18:26:30 +1000 Subject: Booting the linux-ppc64 kernel & flattened device tree v0.4 Message-ID: <1117614390.19020.24.camel@gaston> DO NOT REPLY TO ALL LISTS PLEASE ! (and CC me on replies). Here's the fourth version of my document along with new kernel patches for the new improved flattened format, and the first release of the device-tree "compiler" tool. The patches will be posted as a reply to this email. The compiler, dtc, can be downloaded, the URL is in the document. --- Booting the Linux/ppc64 kernel without Open Firmware ---------------------------------------------------- (c) 2005 Benjamin Herrenschmidt , IBM Corp. May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet. May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or clarifies the fact that a lot of things are optional, the kernel only requires a very small device tree, though it is encouraged to provide an as complete one as possible. May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM - Misc fixes - Define version 3 and new format version 16 for the DT block (version 16 needs kernel patches, will be fwd separately). String block now has a size, and full path is replaced by unit name for more compactness. linux,phandle is made optional, only nodes that are referenced by other nodes need it. "name" property is now automatically deduced from the unit name June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and OF_DT_END_NODE in structure definition. - Change version 16 format to always align property data to 4 bytes. Since tokens are already aligned, that means no specific required alignement between property size and property data. The old style variable alignment would make it impossible to do "simple" insertion of properties using memove (thanks Milton for noticing). Updated kernel patch as well - Correct a few more alignement constraints - Add a chapter about the device-tree compiler and the textural representation of the tree that can be "compiled" by dtc. ToDo: - Add some definitions of interrupt tree (simple/complex) - Add some definitions for pci host bridges I- Introduction =============== During the recent developpements of the Linux/ppc64 kernel, and more specifically, the addition of new platform types outside of the old IBM pSeries/iSeries pair, it was decided to enforce some strict rules regarding the kernel entry and bootloader <-> kernel interfaces, in order to avoid the degeneration that has become the ppc32 kernel entry point and the way a new platform should be added to the kernel. The legacy iSeries platform breaks those rules as it predates this scheme, but no new board support will be accepted in the main tree that doesn't follows them properly. The main requirement that will be defined in more details below is the presence of a device-tree whose format is defined after Open Firmware specification. However, in order to make life easier to embedded board vendors, the kernel doesn't require the device-tree to represent every device in the system and only requires some nodes and properties to be present. This will be described in details in section III, but, for example, the kernel does not require you to create a node for every PCI device in the system. It is a requirement to have a node for PCI host bridges in order to provide interrupt routing informations and memory/IO ranges, among others. It is also recommended to define nodes for on chip devices and other busses that doesn't specifically fit in an existing OF specification, like on chip devices, this creates a great flexibility in the way the kernel can them probe those and match drivers to device, without having to hard code all sorts of tables. It also makes it more flexible for board vendors to do minor hardware upgrades without impacting significantly the kernel code or cluttering it with special cases. 1) Entry point -------------- There is one and one single entry point to the kernel, at the start of the kernel image. That entry point support two calling conventions: a) Boot from Open Firmware. If your firmware is compatible with Open Firmware (IEEE 1275) or provides an OF compatible client interface API (support for "interpret" callback of forth words isn't required), you can enter the kernel with: r5 : OF callback pointer as defined by IEEE 1275 bindings to powerpc. Only the 32 bits client interface is currently supported r3, r4 : address & lenght of an initrd if any or 0 MMU is either on or off, the kernel will run the trampoline located in arch/ppc64/kernel/prom_init.c to extract the device-tree and other informations from open firmware and build a flattened device-tree as described in b). prom_init() will then re-enter the kernel using the second method. This trampoline code runs in the context of the firmware, which is supposed to handle all exceptions during that time. b) Direct entry with a flattened device-tree block. This entry point is called by a) after the OF trampoline and can also be called directly by a bootloader that does not support the Open Firmware client interface. It is also used by "kexec" to implement "hot" booting of a new kernel from a previous running one. This method is what I will describe in more details in this document, as method a) is simply standard Open Firmware, and thus should be implemented according to the various standard documents defining it and it's binding to the PowerPC platform. The entry point definition then becomes: r3 : physical pointer to the device-tree block (defined in chapter II) in RAM r4 : physical pointer to the kernel itself. This is used by the assembly code to properly disable the MMU in case you are entering the kernel with MMU enabled and a non-1:1 mapping. r5 : NULL (as to differenciate with method a) Note about SMP entry: Either your firmware puts your other CPUs in some sleep loop or spin loop in ROM where you can get them out via a soft reset or some other mean, in which case you don't need to care, or you'll have to enter the kernel with all CPUs. The way to do that with method b) will be described in a later revision of this document. 2) Board support ---------------- Board supports (platforms) are not exclusive config options. An arbitrary set of board supports can be built in a single kernel image. The kernel will "known" what set of functions to use for a given platform based on the content of the device-tree. Thus, you should: a) add your platform support as a _boolean_ option in arch/ppc64/Kconfig, following the example of PPC_PSERIES, PPC_PMAC and PPC_MAPLE. The later is probably a good example of a board support to start from. b) create your main platform file as "arch/ppc64/kernel/myboard_setup.c" and add it to the Makefile under the condition of your CONFIG_ option. This file will define a structure of type "ppc_md" containing the various callbacks that the generic code will use to get to your platform specific code c) Add a reference to your "ppc_md" structure in the "machines" table in arch/ppc64/kernel/setup.c d) request and get assigned a platform number (see PLATFORM_* constants in include/asm-ppc64/processor.h I will describe later the boot process and various callbacks that your platform should implement. II - The DT block format =========================== This chapter defines the actual format of the flattened device-tree passed to the kernel. The actual content of it and kernel requirements are described later. You can find example of code manipulating that format in various places, including arch/ppc64/kernel/prom_init.c which will generate a flattened device-tree from the Open Firmware representation, or the fs2dt utility which is part of the kexec tools which will generate one from a filesystem representation. It is expected that a bootloader like uboot provides a bit more support, that will be discussed later as well. Note: The block has to be in main memory. It has to be accessible in both real mode and virtual mode with no other mapping than main memory. If you are writing a simple flash bootloader, it should copy the block to RAM before passing it to the kernel. 1) Header --------- The kernel is entered with r3 pointing to an area of memory that is roughtly described in include/asm-ppc64/prom.h by the structure boot_param_header: struct boot_param_header { u32 magic; /* magic word OF_DT_HEADER */ u32 totalsize; /* total size of DT block */ u32 off_dt_struct; /* offset to structure */ u32 off_dt_strings; /* offset to strings */ u32 off_mem_rsvmap; /* offset to memory reserve map */ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ /* version 2 fields below */ u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ u32 size_dt_strings; /* size of the strings block */ }; Along with the constants: /* Definitions used by the flattened device tree */ #define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ #define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_PROP 0x3 /* Property: name off, size, content */ #define OF_DT_END 0x9 All values in this header are in big endian format, the various fields in this header are defined more precisely below. All "offsets" values are in bytes from the start of the header, that is from r3 value. - magic This is a magic value that "marks" the beginning of the device-tree block header. It contains the value 0xd00dfeed and is defined by the constant OF_DT_HEADER - totalsize This is the total size of the DT block including the header. The "DT" block should enclose all data structures defined in this chapter (who are pointed to by offsets in this header). That is, the device-tree structure, strings, and the memory reserve map. - off_dt_struct This is an offset from the beginning of the header to the start of the "structure" part the device tree. (see 2) device tree) - off_dt_strings This is an offset from the beginning of the header to the start of the "strings" part of the device-tree - off_mem_rsvmap This is an offset from the beginning of the header to the start of the reserved memory map. This map is a list of pairs of 64 bits integers. Each pair is a physical address and a size. The list is terminated by an entry of size 0. This map provides the kernel with a list of physical memory areas that are "reserved" and thus not to be used for memory allocations, especially during early initialisation. The kernel needs to allocate memory during boot for things like un-flattening the device-tree, allocating an MMU hash table, etc... Those allocations must be done in such a way to avoid overriding critical things like, on Open Firmware capable machines, the RTAS instance, or on some pSeries, the TCE tables used for the iommu. Typically, the reserve map should contain _at least_ this DT block itself (header,total_size). If you are passing an initrd to the kernel, you should reserve it as well. You do not need to reserve the kernel image itself. The map should be 64 bits aligned. - version This is the version of this structure. Version 1 stops here. Version 2 adds an additional field boot_cpuid_phys. Version 3 adds the size of the strings block, allowing the kernel to reallocate it easily at boot and free up the unused flattened structure after expansion. Version 16 introduces a new more "compact" format for the tree itself that is however not backward compatible. You should always generate a structure of the highest version defined at the time of your implementation. Currently that is version 16, unless you explicitely aim at being backward compatible - last_comp_version Last compatible version. This indicates down to what version of the DT block you are backward compatible with. For example, version 2 is backward compatible with version 1 (that is, a kernel build for version 1 will be able to boot with a version 2 format). You should put a 1 in this field if you generate a device tree of version 1 to 3, or 0x10 if you generate a tree of version 0x10 using the new unit name format. - boot_cpuid_phys This field only exist on version 2 headers. It indicate which physical CPU ID is calling the kernel entry point. This is used, among others, by kexec. If you are on an SMP system, this value should match the content of the "reg" property of the CPU node in the device-tree corresponding to the CPU calling the kernel entry point (see further chapters for more informations on the required device-tree contents) So the typical layout of a DT block (though the various parts don't need to be in that order) looks like (addresses go from top to bottom): ------------------------------ r3 -> | struct boot_param_header | ------------------------------ | (alignment gap) (*) | ------------------------------ | memory reserve map | ------------------------------ | (alignment gap) | ------------------------------ | | | device-tree structure | | | ------------------------------ | (alignment gap) | ------------------------------ | | | device-tree strings | | | -----> ------------------------------ | | --- (r3 + totalsize) (*) The alignment gaps are not necessarily present, their presence and size are dependent on the various alignment requirements of the individual data blocks. 2) Device tree generalities --------------------------- This device-tree itself is separated in two different blocks, a structure block and a strings block. Both need to be aligned to a 4 bytes boundary. First, let's quickly describe the device-tree concept before detailing the storage format. This chapter does _not_ describe the detail of the required types of nodes & properties for the kernel, this is done later in chapter III. The device-tree layout is strongly inherited from the definition of the Open Firmware IEEE 1275 device-tree. It's basically a tree of nodes, each node having two or more named properties. A property can have a value or not. It is a tree, so each node has one and only one parent except for the root node who has no parent. A node has 2 names. The actual node name is generally contained in a property of type "name" in the node property list whose value is a zero terminated string and is mandatory for version 1 to 3 of the format definition (as it is in Open Firmware). Version 0x10 makes it optional as it can generate it from the unit name defined below. There is also a "unit name" that is used to differenciate nodes with the same name at the same level, it is usually made of the node name's, the "@" sign, and a "unit address", which definition is specific to the bus type the node sits on. The unit name doesn't exist as a property per-se but is included in the device-tree structure. It is typically used to represent "path" in the device-tree. More details about the actual format of these will be below. The kernel ppc64 generic code does not make any formal use of the unit address (though some board support code may do) so the only real requirement here for the unit address is to ensure uniqueness of the node unit name at a given level of the tree. Nodes with no notion of address and no possible sibling of the same name (like /memory or /cpus) may ommit the unit address in the context of this specification, or use the "@0" default unit address. The unit name is used to define a node "full path", which is the concatenation of all parent nodes unit names separated with "/". The root node doesn't have a defined name, and isn't required to have a name property either if you are using version 3 or earlier of the format. It also has no unit address (no @ symbol followed by a unit address). The root node unit name is thus an empty string. The full path to the root node is "/" Every node who actually represents an actual device (that is who isn't only a virtual "container" for more nodes, like "/cpus" is) is also required to have a "device_type" property indicating the type of node Finally, every node that can be referrenced from a property in another node is required to have a "linux,phandle" property. Real open firmware implementations do provide a unique "phandle" value for every node that the "prom_init()" trampoline code turns into "linux,phandle" properties. However, this is made optional if the flattened is used directly. An example of a node referencing another node via "phandle" is when laying out the interrupt tree which will be described in a further version of this document. This propery is a 32 bits value that uniquely identify a node. You are free to use whatever values or system of values, internal pointers, or whatever to generate these, the only requirement is that every node for which you provide that property has a unique value for it. Here is an example of a simple device-tree. In this example, a "o" designates a node followed by the node unit name. Properties are presented with their name followed by their content. "content" represent an ASCII string (zero terminated) value, while represent a 32 bits hexadecimal value. The various nodes in this example will be discusse in a later chapter. At this point, it is only meant to give you a idea of what a device-tree looks like. I have on purpose kept the "name" and "linux,phandle" properties which aren't necessary in order to give you a better idea of what the tree looks like in practice. / o device-tree |- name = "device-tree" |- model = "MyBoardName" |- compatible = "MyBoardFamilyName" |- #address-cells = <2> |- #size-cells = <2> |- linux,phandle = <0> | o cpus | | - name = "cpus" | | - linux,phandle = <1> | | - #address-cells = <1> | | - #size-cells = <0> | | | o PowerPC,970 at 0 | |- name = "PowerPC,970" | |- device_type = "cpu" | |- reg = <0> | |- clock-frequency = <5f5e1000> | |- linux,boot-cpu | |- linux,phandle = <2> | o memory at 0 | |- name = "memory" | |- device_type = "memory" | |- reg = <00000000 00000000 00000000 20000000> | |- linux,phandle = <3> | o chosen |- name = "chosen" |- bootargs = "root=/dev/sda2" |- linux,platform = <00000600> |- linux,phandle = <4> This tree is almost a minimal tree. It pretty much contains the minimal set of required nodes and properties to boot a linux kernel, that is some basic model informations at the root, the CPUs, the physical memory layout, and misc informations passed through /chosen like in this example, the platform type (mandatory) and the kernel command line arguments (optional). The /cpus/PowerPC,970 at 0/linux,boot-cpu property is an example of a property without a value. All other properties have a value. The signification of the #address-cells and #size-cells properties will be explained in chapter IV which defines precisely the required nodes and properties and their content. 3) Device tree "structure" block The structure of the device tree is a linearized tree structure. The "OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE" ends that node definition. Child nodes are simply defined before "OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32 bits value. The tree has to be "finished" with a OF_DT_END token Here's the basic structure of a single node: * token OF_DT_BEGIN_NODE (that is 0x00000001) * for version 1 to 3, this is the node full path as a zero terminated string, starting with "/". For version 16 and later, this is the node unit name only (or an empty string for the root node) * [align gap to next 4 bytes boundary] * for each property: * token OF_DT_PROP (that is 0x00000003) * 32 bits value of property value size in bytes (or 0 of no value) * 32 bits value of offset in string block of property name * property value data if any * [align gap to next 4 bytes boundary] * [child nodes if any] * token OF_DT_END_NODE (that is 0x00000002) So the node content can be summmarised as a start token, a full path, a list of properties, a list of child node and an end token. Every child node is a full node structure itself as defined above 4) Device tree 'strings" block In order to save space, property names, which are generally redundant, are stored separately in the "strings" block. This block is simply the whole bunch of zero terminated strings for all property names concatenated together. The device-tree property definitions in the structure block will contain offset values from the beginning of the strings block. III - Required content of the device tree ========================================= WARNING: All "linux,*" properties defined in this document apply only to a flattened device-tree. If your platform uses a real implementation of Open Firmware or an implementation compatible with the Open Firmware client interface, those properties will be created by the trampoline code in the kernel's prom_init() file. For example, that's where you'll have to add code to detect your board model and set the platform number. However, when using the flatenned device-tree entry point, there is no prom_init() pass, and thus you have to provide those properties yourself. 1) Note about cells and address representation ---------------------------------------------- The general rule is documented in the various Open Firmware documentations. If you chose to describe a bus with the device-tree and there exist an OF bus binding, then you should follow the specification. However, the kernel does not require every single device or bus to be described by the device tree. In general, the format of an address for a device is defined by the parent bus type, based on the #address-cells and #size-cells property. In absence of such a property, the parent's parent values are used, etc... The kernel requires the root node to have those properties defining addresses format for devices directly mapped on the processor bus. Those 2 properties define 'cells' for representing an address and a size. A "cell" is a 32 bits number. For example, if both contain 2 like the example tree given above, then an address and a size are both composed of 2 cells, that is a 64 bits number (cells are concatenated and expected to be in big endian format). Another example is the way Apple firmware define them, that is 2 cells for an address and one cell for a size. A device IO or MMIO areas on the bus are defined in the "reg" property. The format of this property depends on the bus the device is sitting on. Standard bus types define their "reg" properties format in the various OF bindings for those bus types, you are free to define your own "reg" format for proprietary busses or virtual busses enclosing on-chip devices, though it is recommended that the parts of the "reg" property containing addresses and sizes do respect the defined #address-cells and #size-cells when those make sense. Later, I will define more precisely some common address formats. For a new ppc64 board, I recommend to use either the 2/2 format or Apple's 2/1 format which is slightly more compact since sizes usually fit in a single 32 bits word. 2) Note about "compatible" properties ------------------------------------- Those properties are optional, but recommended in devices and the root node. The format of a "compatible" property is a list of concatenated zero terminated strings. They allow a device to express it's compatibility with a family of similar devices, in some cases, allowing a single driver to match against several devices regardless of their actual names 3) Note about "name" properties ------------------------------- While earlier users of Open Firmware like OldWorld macintoshes tended to use the actual device name for the "name" property, it's nowadays considered a good practice to use a name that is closer to the device class (often equal to device_type). For example, nowadays, ethernet controllers are named "ethernet", an additional "model" property defining precisely the chip type/model, and "compatible" property defining the family in case a single driver can driver more than one of these chips. The kernel however doesn't generally put any restriction on the "name" property, it is simply considered good practice to folow the standard and it's evolutions as closely as possible. Note also that the new format version 16 makes the "name" property optional. If it's absent for a node, then the node's unit name is then used to reconstruct the name. That is, the part of the unit name before the "@" sign is used (or the entire unit name if no "@" sign is present). 4) Note about node and property names and character set ------------------------------------------------------- While open firmware provides more flexibe usage of 8859-1, this specification enforces more strict rules. Nodes and properties should be comprised only of ASCII characters 'a' to 'z', '0' to '9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally allow uppercase characters 'A' to 'Z' (property names should be lowercase. The fact that vendors like Apple don't respect this rule is irrelevant here). Additionally, node and property names should always begin with a character in the range 'a' to 'z' (or 'A' to 'Z' for node names). The maximum number of characters for both nodes and property names is 31. In the case of node names, this is only the leftmost part of a unit name (the pure "name" property), it doesn't include the unit address which can extend beyond that limit. 5) Required nodes and properties -------------------------------- a) The root node The root node requires some properties to be present: - model : this is your board name/model - #address-cells : address representation for "root" devices - #size-cells: the size representation for "root" devices Additionally, some recommended properties are: - compatible : the board "family" generally finds its way here, for example, if you have 2 board models with a similar layout, that typically get driven by the same platform code in the kernel, you would use a different "model" property but put a value in "compatible". The kernel doesn't directly use that value (see /chosen/linux,platform for how the kernel choses a platform type) but it is generally useful. It's also generally where you add additional properties specific to your board like the serial number if any, that sort of thing. it is recommended that if you add any "custom" property whose name may clash with standard defined ones, you prefix them with your vendor name and a comma. b) The /cpus node This node is the parent of all individual CPUs nodes. It doesn't have any specific requirements, though it's generally good practice to have at least: #address-cells = <00000001> #size-cells = <00000000> This defines that the "address" for a CPU is a single cell, and has no meaningful size. This is not necessary but the kernel will assume that format when reading the "reg" properties of a CPU node, see below c) The /cpus/* nodes So under /cpus, you are supposed to create a node for every CPU on the machine. There is no specific restriction on the name of the CPU, though It's common practice to call it PowerPC,, for example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX. Required properties: - device_type : has to be "cpu" - reg : This is the physical cpu number, it's single 32 bits cell, this is also used as-is as the unit number for constructing the unit name in the full path, for example, with 2 CPUs, you would have the full path: /cpus/PowerPC,970FX at 0 /cpus/PowerPC,970FX at 1 (unit addresses do not require to have leading zero's) - d-cache-line-size : one cell, L1 data cache line size in bytes - i-cache-line-size : one cell, L1 instruction cache line size in bytes - d-cache-size : one cell, size of L1 data cache in bytes - i-cache-size : one cell, size of L1 instruction cache in bytes Recommended properties: - timebase-frequency : a cell indicating the frequency of the timebase in Hz. This is not directly used by the generic code, but you are welcome to copy/paste the pSeries code for setting the kernel timebase/decrementer calibration based on this value. - clock-frequency : a cell indicating the CPU core clock frequency in Hz. A new property will be defined for 64 bits value, but if your frequency is < 4Ghz, one cell is enough. Here as well as for the above, the common code doesn't use that property, but you are welcome to re-use the pSeries or Maple one. A future kernel version might provide a common function for this. You are welcome to add any property you find relevant to your board, like some informations about mecanism used to soft-reset the CPUs for example (Apple puts the GPIO number for CPU soft reset lines in there as a "soft-reset" property as they start secondary CPUs by soft-resetting them). d) the /memory node(s) To define the physical memory layout of your board, you should create one or more memory node(s). You can either create a single node with all memory ranges in it's reg property, or you can create several nodes, as you wishes. The unit address (@ part) used for the full path is the address of the first range of memory defined by a given node. If you use a single memory node, this will typically be @0. Required properties: - device_type : has to be "memory" - reg : This property contain all the physical memory ranges of your board. It's a list of addresses/sizes concatenated together, the number of cell of those beeing defined by the #address-cells and #size-cells of the root node. For example, with both of these properties beeing 2 like in the example given earlier, a 970 based machine with 6Gb of RAM could typically have a "reg" property here that looks like: 00000000 00000000 00000000 80000000 00000001 00000000 00000001 00000000 That is a range starting at 0 of 0x80000000 bytes and a range starting at 0x100000000 and of 0x100000000 bytes. You can see that there is no memory covering the IO hold between 2Gb and 4Gb. Some vendors prefer splitting those ranges into smaller segments, the kernel doesn't care. c) The /chosen node This node is a bit "special". Normally, that's where open firmware puts some variable environment informations, like the arguments, or phandle pointers to nodes like the main interrupt controller, or the default input/output devices. This specification makes a few of these mandatory, but also defines some linux specific properties that would be normally constructed by the prom_init() trampoline when booting with an OF client interface, but that you have to provide yourself when using the flattened format. Required properties: - linux,platform : This is your platform number as assigned by the architecture maintainers Recommended properties: - bootargs : This zero terminated string is passed as the kernel command line - linux,stdout-path : This is the full path to your standard console device if any. Typically, if you have serial devices on your board, you may want to put the full path to the one set as the default console in the firmware here, for the kernel to pick it up as it's own default console. If you look at the funciton set_preferred_console() in arch/ppc64/kernel/setup.c, you'll see that the kernel tries to find out the default console and has knowledge of various types like 8250 serial ports. You may want to extend this function to add your own. - interrupt-controller : This is one cell containing a phandle value that matches the "linux,phandle" property of your main interrupt controller node. May be used for interrupt routing. This is all that is currently required. However, it is strongly recommended that you expose PCI host bridges as documented in the PCI binding to open firmware, and your interrupt tree as documented in OF interrupt tree specification. IV - "dtc", the device tree compiler ==================================== dtc source code can be found at WARNING: This version is still in early developpement stage, the resulting device-tree "blobs" have not yet been validated with the kernel. The current generated bloc lacks a useful reserve map (it will be fixed to generate an empty one, it's up to the bootloader to fill it up) among others. The error handling needs work, bugs are lurking, etc... dtc basically takes a device-tree in a given format and outputs a device-tree in another format. The currently supported formats are: Input formats: ------------- - "dtb": "blob" format, that is a flattened device-tree block with header all in a binary blob. - "dts": "source" format. This is a text file containing a "source" for a device-tree. The format is defined later in this chapter. - "fs" format. This is a representation equivalent to the output of /proc/device-tree, that is nodes are directories and properties are files Output formats: --------------- - "dtb": "blob" format - "dts": "source" format - "asm": assembly language file. This is a file that can be sourced by gas to generate a device-tree "blob". That file can then simply be added to your Makefile. Additionally, the assembly file exports some symbols that can be use The syntax of the dtc tool is dtc [-I ] [-O ] [-o output-filename] [-V output_version] input_filename The "output_version" defines what versio of the "blob" format will be generated. Supported versions are 1,2,3 and 16. The default is currently version 3 but that may change in the future to version 16. Additionally, dtc performs various sanity checks on the tree, like the uniqueness of linux,phandle properties, validity of strings, etc... The format of the .dts "source" file is "C" like, supports C and C++ style commments. / { } The above is the "device-tree" definition. It's the only statement supported currently at the toplevel. / { property1 = "string_value"; /* define a property containing a 0 * terminated string */ property2 = <1234abcd>; /* define a property containing a * numerical 32 bits value (hexadecimal) */ property3 = <12345678 12345678 deadbeef>; /* define a property containing 3 numerical * 32 bits values (cells) in * hexadecimal */ property4 = [0a 0b 0c 0d de ea ad be ef]; /* define a property whose content is * an arbitrary array of bytes */ childnode at addresss { /* define a child node named "childnode" * whose unit name is "childnode at address" */ childprop = "hello\n"; /* define a property "childprop" of * childnode (in this case, a string) */ }; }; Nodes can contain other nodes etc... thus defining the hierarchical structure of the tree. Strings support common escape sequences from C: "\n", "\t", "\r", "\(octal value)", "\x(hex value)". It is also suggested that you pipe your source file through cpp (gcc preprocessor) so you can use #include's, #define for constants, etc... Finally, various options are planned but not yet implemented, like automatic generation of phandles, labels (exported to the asm file so you can point to a property content and change it easily from whatever you link the device-tree with), label or path instead of numeric value in some cells to "point" to a node (replaced by a phandle at compile time), export of reserve map address to the asm file, ability to specify reserve map content at compile time, etc... We may provide a .h include file with common definitions of that proves useful for some properties (like building PCI properties or interrupt maps) though it may be better to add a notion of struct definitions to the compiler... V - Recommendation for a bootloader =================================== Here are some various ideas/recommendations that have been proposed while all this has been defined and implemented. - A very The bootloader may want to be able to use the device-tree itself and may want to manipulate it (to add/edit some properties, like physical memory size or kernel arguments). At this point, 2 choices can be made. Either the bootloader works directly on the flattened format, or the bootloader has it's own internal tree representation with pointers (similar to the kernel one) and re-flattens the tree when booting the kernel. The former is a bit more difficult to edit/modify, the later requires probably a bit more code to handle the tree structure. Note that the structure format has been designed so it's relatively easy to "insert" properties or nodes or delete them by just memmovin'g things around. It contains no internal offsets or pointers for this purpose. - An example of code for iterating nodes & retreiving properties directly from the flattened tree format can be found in the kernel file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function, it's usage in early_init_devtree(), and the corresponding various early_init_dt_scan_*() callbacks. That code can be re-used in a GPL bootloader, and as the author of that code, I would be happy do discuss possible free licencing to any vendor who wishes to integrate all or part of this code into a non-GPL bootloader. From benh at kernel.crashing.org Wed Jun 1 18:28:03 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 18:28:03 +1000 Subject: Booting the linux-ppc64 kernel & flattened device tree v0.4 In-Reply-To: <1117614390.19020.24.camel@gaston> References: <1117614390.19020.24.camel@gaston> Message-ID: <1117614484.19020.27.camel@gaston> Here is the kernel patch. It applies on top of the various prom_init.c bug fixes that I already posted today on the linuxppc-dev & linuxppc64-dev lists (those will be in the next -mm and maybe in 2.6.12). This patch is intended to hit upstream by 2.6.13 Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-01 16:02:28.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-01 16:07:21.000000000 +1000 @@ -1514,7 +1514,14 @@ return 0; } -static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + +static void __init scan_dt_build_strings(phandle node, + unsigned long *mem_start, unsigned long *mem_end) { unsigned long offset = reloc_offset(); @@ -1527,14 +1534,19 @@ /* get and store all property names */ prev_name = RELOC(""); for (;;) { - - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, 32, 1); + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; } + + /* skip "name" */ + if (strcmp(namep, RELOC("name")) == 0) { + *mem_start = (unsigned long)namep; + prev_name = RELOC("name"); + continue; + } soff = dt_find_string(namep); if (soff != 0) { *mem_start = (unsigned long)namep; @@ -1555,72 +1567,83 @@ } } -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { - int l, align; phandle child; - char *namep, *prev_name, *sstart, *p, *ep; + char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; unsigned long soff; unsigned char *valp; unsigned long offset = reloc_offset(); - char pname[MAX_PROPERTY_NAME]; - char *path; - - path = RELOC(prom_scratch); + static char pname[MAX_PROPERTY_NAME] __initdata; + int l; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); - /* get the node's full name */ + /* get the node's full name for debugging */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + prom_debug(" %s\n", path); + + /* get the node's full name for actual use */ namep = (char *)*mem_start; l = call_prom("package-to-path", 3, 1, node, namep, *mem_end - *mem_start); if (l >= 0) { + int had_fixup = 0; + /* Didn't fit? Get more room. */ if (l+1 > *mem_end - *mem_start) { namep = make_room(mem_start, mem_end, l+1, 1); call_prom("package-to-path", 3, 1, node, namep, l); } - namep[l] = '\0'; - /* Fixup an Apple bug where they have bogus \0 chars in the - * middle of the path in some properties - */ - for (p = namep, ep = namep + l; p < ep; p++) - if (*p == '\0') { - memmove(p, p+1, ep - p); - ep--; l--; - } - *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); + ep = namep + l; + *ep = '\0'; + /* now try to find the unit name in that mess */ + for (p = namep, lp = NULL; p < ep; p++) { + if (*p == '/') + lp = p + 1; + /* bug fix: apple's OF has a funny bug where they have + * a '\0' in the name/path string of some nodes. + * We fix that up here + */ + if (*p == '\0') { + memmove(p, p+1, ep - p); + ep--; l--; + had_fixup = 1; + } + } + if (had_fixup) + prom_printf("fixed up bogus name for %s\n", namep); + if (lp != NULL) + memmove(namep, lp, strlen(lp) + 1); + *mem_start = _ALIGN(((unsigned long) namep) + + strlen(namep) + 1, 4); } - /* get it again for debugging */ - memset(path, 0, PROM_SCRATCH_SIZE); - call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); - /* get and store all properties */ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) - break; - - /* find string offset */ - soff = dt_find_string(pname); + if (call_prom("nextprop", 3, 1, node, prev_name, + RELOC(pname)) <= 0) + break; + if (strcmp(RELOC(pname), RELOC("name")) == 0) { + prev_name = RELOC("name"); + continue; + } + /* find string offset */ + soff = dt_find_string(RELOC(pname)); if (soff == 0) { - prom_printf("WARNING: Can't find string index for <%s>, node %s\n", - pname, path); + prom_printf("WARNING: Can't find string index " + "for <%s>, node %s\n", RELOC(pname), path); break; } prev_name = sstart + soff; /* get length */ - l = call_prom("getproplen", 2, 1, node, pname); + l = call_prom("getproplen", 2, 1, node, RELOC(pname)); /* sanity checks */ if (l < 0) @@ -1629,7 +1652,7 @@ prom_printf("WARNING: ignoring large property "); /* It seems OF doesn't null-terminate the path :-( */ prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", pname, l); + prom_printf("%s length 0x%x\n", RELOC(pname), l); continue; } @@ -1639,17 +1662,16 @@ dt_push_token(soff, mem_start, mem_end); /* push property content */ - align = (l >= 8) ? 8 : 4; - valp = make_room(mem_start, mem_end, l, align); - call_prom("getprop", 4, 1, node, pname, valp, l); + valp = make_room(mem_start, mem_end, l, 4); + call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); *mem_start = _ALIGN(*mem_start, 4); } /* Add a "linux,phandle" property. */ soff = dt_find_string(RELOC("linux,phandle")); if (soff == 0) - prom_printf("WARNING: Can't find string index for " - " node %s\n", path); + prom_printf("WARNING: Can't find string index for" + " node %s\n", path); else { dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(4, mem_start, mem_end); @@ -1699,7 +1721,8 @@ /* Build header and make room for mem rsv map */ mem_start = _ALIGN(mem_start, 4); - hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); + hdr = make_room(&mem_start, &mem_end, + sizeof(struct boot_param_header), 4); RELOC(dt_header_start) = (unsigned long)hdr; rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); @@ -1712,11 +1735,11 @@ namep = make_room(&mem_start, &mem_end, 16, 1); strcpy(namep, RELOC("linux,phandle")); mem_start = (unsigned long)namep + strlen(namep) + 1; - RELOC(dt_string_end) = mem_start; /* Build string array */ prom_printf("Building dt strings...\n"); scan_dt_build_strings(root, &mem_start, &mem_end); + RELOC(dt_string_end) = mem_start; /* Build structure */ mem_start = PAGE_ALIGN(mem_start); @@ -1731,9 +1754,11 @@ hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); hdr->version = OF_DT_VERSION; - hdr->last_comp_version = 1; + /* Version 16 is not backward compatible */ + hdr->last_comp_version = 0x10; /* Reserve the whole thing and copy the reserve map in, we * also bump mem_reserve_cnt to cause further reservations to @@ -1788,6 +1813,9 @@ /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) return; + + prom_printf("fixing up bogus interrupts for u3 i2c...\n"); + /* interrupt on this revision of u3 is number 0 and level */ interrupts[0] = 0; interrupts[1] = 1; Index: linux-work/arch/ppc64/kernel/setup.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/setup.c 2005-06-01 16:02:28.000000000 +1000 +++ linux-work/arch/ppc64/kernel/setup.c 2005-06-01 16:07:21.000000000 +1000 @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG +#define DEBUG #include #include Index: linux-work/arch/ppc64/kernel/prom.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom.c 2005-06-01 16:02:28.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom.c 2005-06-01 16:07:21.000000000 +1000 @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG +#define DEBUG #include #include @@ -635,26 +635,32 @@ * unflatten the tree */ static int __init scan_flat_dt(int (*it)(unsigned long node, - const char *full_path, void *data), + const char *uname, int depth, void *data), void *data) { unsigned long p = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; int rc = 0; + int depth = -1; do { u32 tag = *((u32 *)p); char *pathp; p += 4; - if (tag == OF_DT_END_NODE) + if (tag == OF_DT_END_NODE) { + depth --; + continue; + } + if (tag == OF_DT_NOP) continue; if (tag == OF_DT_END) break; if (tag == OF_DT_PROP) { u32 sz = *((u32 *)p); p += 8; - p = _ALIGN(p, sz >= 8 ? 8 : 4); + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); p += sz; p = _ALIGN(p, 4); continue; @@ -664,9 +670,18 @@ " device tree !\n", tag); return -EINVAL; } + depth++; pathp = (char *)p; p = _ALIGN(p + strlen(pathp) + 1, 4); - rc = it(p, pathp, data); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); if (rc != 0) break; } while(1); @@ -689,13 +704,16 @@ const char *nstr; p += 4; + if (tag == OF_DT_NOP) + continue; if (tag != OF_DT_PROP) return NULL; sz = *((u32 *)p); noff = *((u32 *)(p + 4)); p += 8; - p = _ALIGN(p, sz >= 8 ? 8 : 4); + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); if (nstr == NULL) { @@ -713,7 +731,7 @@ } static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, - unsigned long align) + unsigned long align) { void *res; @@ -727,13 +745,16 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, unsigned long *p, struct device_node *dad, - struct device_node ***allnextpp) + struct device_node ***allnextpp, + unsigned long fpsize) { struct device_node *np; struct property *pp, **prev_pp = NULL; char *pathp; u32 tag; - unsigned int l; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; tag = *((u32 *)(*p)); if (tag != OF_DT_BEGIN_NODE) { @@ -742,21 +763,62 @@ } *p += 4; pathp = (char *)*p; - l = strlen(pathp) + 1; + l = allocl = strlen(pathp) + 1; *p = _ALIGN(*p + l, 4); - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } else { + /* account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); if (allnextpp) { memset(np, 0, sizeof(*np)); np->full_name = ((char*)np) + sizeof(struct device_node); - memcpy(np->full_name, pathp, l); + if (new_format) { + char *p = np->full_name; + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(p, dad->full_name); +#ifdef DEBUG + if ((strlen(p) + l + 1) != allocl) { + DBG("%s: p: %d, l: %d, a: %d\n", + pathp, strlen(p), l, allocl); + } +#endif + p += strlen(p); + } + *(p++) = '/'; + memcpy(p, pathp, l); + } else + memcpy(np->full_name, pathp, l); prev_pp = &np->properties; **allnextpp = np; *allnextpp = &np->allnext; if (dad != NULL) { np->parent = dad; - /* we temporarily use the `next' field as `last_child'. */ + /* we temporarily use the next field as `last_child'*/ if (dad->next == 0) dad->child = np; else @@ -770,18 +832,26 @@ char *pname; tag = *((u32 *)(*p)); + if (tag == OF_DT_NOP) { + *p += 4; + continue; + } if (tag != OF_DT_PROP) break; *p += 4; sz = *((u32 *)(*p)); noff = *((u32 *)((*p) + 4)); - *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); + *p += 8; + if (initial_boot_params->version < 0x10) + *p = _ALIGN(*p, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); if (pname == NULL) { printk("Can't find property name in list !\n"); break; } + if (strcmp(pname, "name") == 0) + has_name = 1; l = strlen(pname) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); @@ -801,6 +871,28 @@ } *p = _ALIGN((*p) + sz, 4); } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + char *pa = pathp; + int sz; + + while (*pa && (*pa) != '@') + pa++; + sz = (pa - pathp) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (allnextpp) { + pp->name = "name"; + pp->length = sz; + pp->value = (unsigned char *)(pp + 1); + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, pathp, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + } + } if (allnextpp) { *prev_pp = NULL; np->name = get_property(np, "name", NULL); @@ -812,7 +904,7 @@ np->type = ""; } while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp); + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); tag = *((u32 *)(*p)); } if (tag != OF_DT_END_NODE) { @@ -842,7 +934,7 @@ /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - size = unflatten_dt_node(0, &start, NULL, NULL); + size = unflatten_dt_node(0, &start, NULL, NULL, 0); DBG(" size is %lx, allocating...\n", size); @@ -854,7 +946,7 @@ /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - unflatten_dt_node(mem, &start, NULL, &allnextp); + unflatten_dt_node(mem, &start, NULL, &allnextp, 0); if (*((u32 *)start) != OF_DT_END) printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); *allnextp = NULL; @@ -880,7 +972,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { char *type = get_flat_dt_prop(node, "device_type", NULL); u32 *prop; @@ -933,13 +1025,15 @@ } static int __init early_init_dt_scan_chosen(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { u32 *prop; u64 *prop64; extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; - if (strcmp(full_path, "/chosen") != 0) + DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + + if (depth != 1 || strcmp(uname, "chosen") != 0) return 0; /* get platform type */ @@ -989,18 +1083,20 @@ } static int __init early_init_dt_scan_root(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { u32 *prop; - if (strcmp(full_path, "/") != 0) + if (depth != 0) return 0; prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); dt_root_size_cells = (prop == NULL) ? 1 : *prop; - + DBG("dt_root_size_cells = %x\n", dt_root_size_cells); + prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ return 1; @@ -1028,7 +1124,7 @@ static int __init early_init_dt_scan_memory(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { char *type = get_flat_dt_prop(node, "device_type", NULL); cell_t *reg, *endp; @@ -1044,7 +1140,9 @@ endp = reg + (l / sizeof(cell_t)); - DBG("memory scan node %s ...\n", full_path); + DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n", + uname, l, reg[0], reg[1], reg[2], reg[3]); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { unsigned long base, size; @@ -1455,10 +1553,11 @@ struct device_node *np = allnodes; read_lock(&devtree_lock); - for (; np != 0; np = np->allnext) + for (; np != 0; np = np->allnext) { if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 && of_node_get(np)) break; + } read_unlock(&devtree_lock); return np; } Index: linux-work/include/asm-ppc64/prom.h =================================================================== --- linux-work.orig/include/asm-ppc64/prom.h 2005-06-01 16:07:18.000000000 +1000 +++ linux-work/include/asm-ppc64/prom.h 2005-06-01 16:07:21.000000000 +1000 @@ -22,13 +22,15 @@ #define RELOC(x) (*PTRRELOC(&(x))) /* Definitions used by the flattened device tree */ -#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ -#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ #define OF_DT_END_NODE 0x2 /* End node */ -#define OF_DT_PROP 0x3 /* Property: name off, size, content */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ #define OF_DT_END 0x9 -#define OF_DT_VERSION 1 +#define OF_DT_VERSION 0x10 /* * This is what gets passed to the kernel by prom_init or kexec @@ -54,7 +56,9 @@ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ /* version 2 fields below */ - u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ }; From arnd at arndb.de Wed Jun 1 19:07:31 2005 From: arnd at arndb.de (Arnd Bergmann) Date: Wed, 1 Jun 2005 11:07:31 +0200 Subject: [PATCH] ppc64: fix fixup_device_tree Message-ID: <200506011107.31751.arnd@arndb.de> The new fixup_device_tree function breaks on some open firmware implementations that can't deal with invalid phandle values passed to prom_getprop(). The current code attempts to check the validity of the phandle returned from finddevice but fails to do that correctly, because (0x00000000fffffffful <= 0) is false. I suggest comparing the returned phandle to the expected value directly. Signed-off-by: Arnd Bergmann References: <200506011107.31751.arnd@arndb.de> Message-ID: <17053.36293.360808.42984@cargo.ozlabs.ibm.com> Arnd Bergmann writes: > - if ((long)u3 <= 0) > + if (u3 == -1u) Yes, OK, but I think I would prefer either "-1" or "~0U" to "-1u". Paul. From benh at kernel.crashing.org Wed Jun 1 20:42:40 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Wed, 01 Jun 2005 20:42:40 +1000 Subject: [PATCH] ppc64: fix fixup_device_tree In-Reply-To: <200506011107.31751.arnd@arndb.de> References: <200506011107.31751.arnd@arndb.de> Message-ID: <1117622561.19020.38.camel@gaston> On Wed, 2005-06-01 at 11:07 +0200, Arnd Bergmann wrote: > The new fixup_device_tree function breaks on some open firmware > implementations that can't deal with invalid phandle values passed > to prom_getprop(). > The current code attempts to check the validity of the phandle > returned from finddevice but fails to do that correctly, because > (0x00000000fffffffful <= 0) is false. > I suggest comparing the returned phandle to the expected > value directly. Ah indeed. There are a couple of other cases that get it wrong btw. I'll send a patch tomorrow. Ben. From brking at us.ibm.com Thu Jun 2 00:09:25 2005 From: brking at us.ibm.com (Brian King) Date: Wed, 01 Jun 2005 09:09:25 -0500 Subject: [PATCH]: PCI Error Recovery Implementation In-Reply-To: <20050531203028.GD31199@austin.ibm.com> References: <20050531203028.GD31199@austin.ibm.com> Message-ID: <429DC195.1010801@us.ibm.com> What tree is this patch diffed from? It doesn't apply to the current 2.6.12-rc5-git6 snapshot on kernel.org. Also, when you re-diff, can you diff in patch -p1 format so that akpm's patch scripts work on it? Thanks -Brian Linas Vepstas wrote: > > Hi, > > Attached is the latest and greatest greatest PCI error recovery > patch. Its posted here as one giant patch, but logically consists > of a number of different pieces: > > 1) generic modifications to include/linux/pci.h, as per emails > in last round of discussion. > > 2) Documentation/pci-error-recovery.txt describing the API. > This is a cut-n-paste-modified copy of BenH's email. > I changed the names of a few routines, and added notes > about the current ppc64 implementation. > > 3) working patches to the SCSI ipr and symbios device drivers > to use this API to recover from PCI errors. These actually work. > I plan to have a patch for e1000 "real soon now"(TM). > > 4) ppc64-specific patches that use the API to notify the device > of PCI errors. > > Please review. I want to get this submitted into mainline ASAP. > > --linas > > Signed-off-by: Linas Vepstas > > > ------------------------------------------------------------------------ > > --- include/linux/pci.h.linas-orig 2005-04-29 20:27:22.000000000 -0500 > +++ include/linux/pci.h 2005-05-31 13:47:46.000000000 -0500 > @@ -659,6 +659,81 @@ struct pci_dynids { > unsigned int use_driver_data:1; /* pci_driver->driver_data is used */ > }; > > +/* ---------------------------------------------------------------- */ > +/** PCI error recovery infrastructure. If a PCI device driver provides > + * a set fof callbacks in struct pci_error_handlers, then that device driver > + * will be notified of PCI bus errors, and can be driven to recovery. > + */ > + > +enum pci_channel_state { > + pci_channel_io_normal = 0, /* I/O channel is in normal state */ > + pci_channel_io_frozen = 1, /* I/O to channel is blocked */ > + pci_channel_io_perm_failure, /* pci card is dead */ > +}; > + > +enum pcierr_result { > + PCIERR_RESULT_NONE=0, /* no result/none/not supported in device driver */ > + PCIERR_RESULT_CAN_RECOVER=1, /* Device driver can recover without slot reset */ > + PCIERR_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */ > + PCIERR_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */ > + PCIERR_RESULT_RECOVERED, /* Device driver is fully recovered and operational */ > +}; > + > +/* PCI bus error event callbacks */ > +struct pci_error_handlers > +{ > + int (*error_detected)(struct pci_dev *dev, enum pci_channel_state error); > + int (*mmio_enabled)(struct pci_dev *dev); /* MMIO has been reanbled, but not DMA */ > + int (*link_reset)(struct pci_dev *dev); /* PCI Express link has been reset */ > + int (*slot_reset)(struct pci_dev *dev); /* PCI slot has been reset */ > + void (*resume)(struct pci_dev *dev); /* Device driver may resume normal operations */ > +}; > + > +/** > + * PCI Error notifier event flags. > + */ > +#define PEH_NOTIFY_ERROR 1 > + > +/** PEH event -- structure holding pci controller data that describes > + * a change in the isolation status of a PCI slot. A pointer > + * to this struct is passed as the data pointer in a notify callback. > + */ > +struct peh_event { > + struct list_head list; > + struct pci_dev *dev; /* affected device */ > + enum pci_channel_state state; /* PCI bus state for the affected device */ > + int time_unavail; /* milliseconds until device might be available */ > +}; > + > +/** > + * peh_send_failure_event - generate a PCI error event > + * @dev pci device > + * > + * This routine builds a PCI error event which will be delivered > + * to all listeners on the peh_notifier_chain. > + * > + * This routine can be called within an interrupt context; > + * the actual event will be delivered in a normal context > + * (from a workqueue). > + */ > +int peh_send_failure_event (struct pci_dev *dev, > + enum pci_channel_state state, > + int time_unavail); > + > +/** > + * peh_register_notifier - Register to find out about EEH events. > + * @nb: notifier block to callback on events > + */ > +int peh_register_notifier(struct notifier_block *nb); > + > +/** > + * peh_unregister_notifier - Unregister to an EEH event notifier. > + * @nb: notifier block to callback on events > + */ > +int peh_unregister_notifier(struct notifier_block *nb); > + > +/* ---------------------------------------------------------------- */ > + > struct module; > struct pci_driver { > struct list_head node; > @@ -671,6 +746,7 @@ struct pci_driver { > int (*resume) (struct pci_dev *dev); /* Device woken up */ > int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ > > + struct pci_error_handlers err_handler; > struct device_driver driver; > struct pci_dynids dynids; > }; > --- Documentation/pci-error-recovery.txt.linas-orig 2005-05-06 17:44:41.000000000 -0500 > +++ Documentation/pci-error-recovery.txt 2005-05-31 15:08:56.000000000 -0500 > @@ -0,0 +1,232 @@ > + > + PCI Error Recovery > + ------------------ > + May 31, 2005 > + > + > +Some PCI bus controllers are able to detect certain "hard" PCI errors > +on the bus, such as parity errors on the data and address busses, as > +well as SERR and PERR errors. These chipsets are then able to disable > +I/O to/from the affected device, so that, for example, a bad DMA > +address doesn't end up corrupting system memory. These same chipsets > +are also able to reset the affected PCI device, and return it to > +working condition. This document describes a generic API form > +performing error recovery. > + > +The core idea is that after a PCI error has been detected, there must > +be a way for the kernel to coordinate with all affected device drivers > +so that the pci card can be made operational again, possibly after > +performing a full electrical #RST of the PCI card. The API below > +provides a generic API for device drivers to be notified of PCI > +errors, and to be notified of, and respond to, a reset sequence. > + > +Preliminary sketch of API, cut-n-pasted-n-modified email from > +Ben Herrenschmidt, circa 5 april 2005 > + > +The error recovery API support is exposed to the driver in the form of > +a structure of function pointers pointed to by a new field in struct > +pci_driver. The absence of this pointer in pci_driver denotes an > +"non-aware" driver, behaviour on these is platform dependant. > +Platforms like ppc64 can try to simulate pci hotplug remove/add. > + > +The definition of "pci_error_token" is not covered here. It is based on > +Seto's work on the synchronous error detection. We still need to define > +functions for extracting infos out of an opaque error token. This is > +separate from this API. > + > +This structure has the form: > + > +struct pci_error_handlers > +{ > + int (*error_detected)(struct pci_dev *dev, pci_error_token error); > + int (*mmio_enabled)(struct pci_dev *dev); > + int (*resume)(struct pci_dev *dev); > + int (*link_reset)(struct pci_dev *dev); > + int (*slot_reset)(struct pci_dev *dev); > +}; > + > +A driver doesn't have to implement all of these callbacks. The > +only mandatory one is error_detected(). If a callback is not > +implemented, the corresponding feature is considered unsupported. > +For example, if mmio_enabled() and resume() aren't there, then the > +driver is assumed as not doing any direct recovery and requires > +a reset. If link_reset() is not implemented, the card is assumed as > +not caring about link resets, in which case, if recover is supported, > +the core can try recover (but not slot_reset() unless it really did > +reset the slot). If slot_reset() is not supported, link_reset() can > +be called instead on a slot reset. > + > +At first, the call will always be : > + > + 1) error_detected() > + > + Error detected. This is sent once after an error has been detected. At > +this point, the device might not be accessible anymore depending on the > +platform (the slot will be isolated on ppc64). The driver may already > +have "noticed" the error because of a failing IO, but this is the proper > +"synchronisation point", that is, it gives a chance to the driver to > +cleanup, waiting for pending stuff (timers, whatever, etc...) to > +complete; it can take semaphores, schedule, etc... everything but touch > +the device. Within this function and after it returns, the driver > +shouldn't do any new IOs. Called in task context. This is sort of a > +"quiesce" point. See note about interrupts at the end of this doc. > + > + Result codes: > + - PCIERR_RESULT_CAN_RECOVER: > + Driever returns this if it thinks it might be able to recover > + the HW by just banging IOs or if it wants to be given > + a chance to extract some diagnostic informations (see > + below). > + - PCIERR_RESULT_NEED_RESET: > + Driver returns this if it thinks it can't recover unless the > + slot is reset. > + - PCIERR_RESULT_DISCONNECT: > + Return this if driver thinks it won't recover at all, > + (this will detach the driver ? or just leave it > + dangling ? to be decided) > + > +So at this point, we have called error_detected() for all drivers > +on the segment that had the error. On ppc64, the slot is isolated. What > +happens now typically depends on the result from the drivers. If all > +drivers on the segment/slot return PCIERR_RESULT_CAN_RECOVER, we would > +re-enable IOs on the slot (or do nothing special if the platform doesn't > +isolate slots) and call 2). If not and we can reset slots, we go to 4), > +if neither, we have a dead slot. If it's an hotplug slot, we might > +"simulate" reset by triggering HW unplug/replug though. > + > +>>> Current ppc64 implementation assumes that a device driver will > +>>> *not* schedule or semaphore in this routine; the current ppc64 > +>>> implementation uses one kernel thread to notify all devices; > +>>> thus, of one device sleeps/schedules, all devices are affected. > +>>> Doing better requires complex multi-threaded logic in the error > +>>> recovery implementation (e.g. waiting for all notification threads > +>>> to "join" before proceeding with recovery.) This seems excessively > +>>> complex and not worth implementing. > + > + 2) mmio_enabled() > + > + This is the "early recovery" call. IOs are allowed again, but DMA is > +not (hrm... to be discussed, I prefer not), with some restrictions. This > +is NOT a callback for the driver to start operations again, only to > +peek/poke at the device, extract diagnostic information, if any, and > +eventually do things like trigger a device local reset or some such, > +but not restart operations. This is sent if all drivers on a segment > +agree that they can try to recover and no automatic link reset was > +performed by the HW. If the platform can't just re-enable IOs without > +a slot reset or a link reset, it doesn't call this callback and goes > +directly to 3) or 4). All IOs should be done _synchronously_ from > +within this callback, errors triggered by them will be returned via > +the normal pci_check_whatever() api, no new error_detected() callback > +will be issued due to an error happening here. However, such an error > +might cause IOs to be re-blocked for the whole segment, and thus > +invalidate the recovery that other devices on the same segment might > +have done, forcing the whole segment into one of the next states, > +that is link reset or slot reset. > + > + Result codes: > + - PCIERR_RESULT_RECOVERED > + Driver returns this if it thinks the device is fully > + functionnal and thinks it is ready to start > + normal driver operations again. There is no > + guarantee that the driver will actually be > + allowed to proceed, as another driver on the > + same segment might have failed and thus triggered a > + slot reset on platforms that support it. > + > + - PCIERR_RESULT_NEED_RESET > + Driver returns this if it thinks the device is not > + recoverable in it's current state and it needs a slot > + reset to proceed. > + > + - PCIERR_RESULT_DISCONNECT > + Same as above. Total failure, no recovery even after > + reset driver dead. (To be defined more precisely) > + > +>>> The current ppc64 implementation does not implement this callback. > + > + 3) link_reset() > + > + This is called after the link has been reset. This is typically > +a PCI Express specific state at this point and is done whenever a > +non-fatal error has been detected that can be "solved" by resetting > +the link. This call informs the driver of the reset and the driver > +should check if the device appears to be in working condition. > +This function acts a bit like 2) mmio_enabled(), in that the driver > +is not supposed to restart normal driver I/O operations right away. > +Instead, it should just "probe" the device to check it's recoverability > +status. If all is right, then the core will call resume() once all > +drivers have ack'd link_reset(). > + > + Result codes: > + (identical to mmio_enabled) > + > +>>> The current ppc64 implementation does not implement this callback. > + > + 4) slot_reset() > + > + This is called after the slot has been soft or hard reset by the > +platform. A soft reset consists of asserting the adapter #RST line > +and then restoring the PCI BARs and PCI configuration header. If the > +platform supports PCI hotplug, then it might instead perform a hard > +reset by toggling power on the slot off/on. This call gives drivers > +the chance to re-initialize the hardware (re-download firmware, etc.), > +but drivers shouldn't restart normal I/O processing operations at > +this point. (See note about interrupts; interrupts aren't guaranteed > +to be delivered until the resume() callback has been called). If all > +device drivers report success on this callback, the patform will call > +resume() to complete the error handling and let the driver restart > +normal I/O processing. > + > +A driver can still return a critical failure for this function if > +it can't get the device operational after reset. If the platform > +previously tried a soft reset, it migh now try a hard reset (power > +cycle) and then call slot_reset() again. It the device still can't > +be recovered, there is nothing more that can be done; the platform > +will typically report a "permanent failure" in such a case. The > +device will be considered "dead" in this case. > + > + Result codes: > + - PCIERR_RESULT_DISCONNECT > + Same as above. > + > + 5) resume() > + > + This is called if all drivers on the segment have returned > +PCIERR_RESULT_RECOVERED from one of the 3 prevous callbacks. > +That basically tells the driver to restart activity, tht everything > +is back and running. No result code is taken into account here. If > +a new error happens, it will restart a new error handling process. > + > +That's it. I think this covers all the possibilities. The way those > +callbacks are called is platform policy. A platform with no slot reset > +capability for example may want to just "ignore" drivers that can't > +recover (disconnect them) and try to let other cards on the same segment > +recover. Keep in mind that in most real life cases, though, there will > +be only one driver per segment. > + > +Now, there is a note about interrupts. If you get an interrupt and your > +device is dead or has been isolated, there is a problem :) > + > +After much thinking, I decided to leave that to the platform. That is, > +the recovery API only precies that: > + > + - There is no guarantee that interrupt delivery can proceed from any > +device on the segment starting from the error detection and until the > +restart callback is sent, at which point interrupts are expected to be > +fully operational. > + > + - There is no guarantee that interrupt delivery is stopped, that is, ad > +river that gets an interrupts after detecting an error, or that detects > +and error within the interrupt handler such that it prevents proper > +ack'ing of the interrupt (and thus removal of the source) should just > +return IRQ_NOTHANDLED. It's up to the platform to deal with taht > +condition, typically by masking the irq source during the duration of > +the error handling. It is expected that the platform "knows" which > +interrupts are routed to error-management capable slots and can deal > +with temporarily disabling that irq number during error processing (this > +isn't terribly complex). That means some IRQ latency for other devices > +sharing the interrupt, but there is simply no other way. High end > +platforms aren't supposed to share interrupts between many devices > +anyway :) > + > + > --- drivers/pci/Makefile.linas-orig 2005-04-29 20:31:33.000000000 -0500 > +++ drivers/pci/Makefile 2005-05-06 12:28:43.000000000 -0500 > @@ -3,7 +3,7 @@ > # > > obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ > - names.o pci-driver.o search.o pci-sysfs.o \ > + names.o pci-driver.o pci-error.o search.o pci-sysfs.o \ > rom.o > obj-$(CONFIG_PROC_FS) += proc.o > > --- drivers/pci/pci-error.c.linas-orig 2005-05-06 17:44:47.000000000 -0500 > +++ drivers/pci/pci-error.c 2005-05-31 13:49:34.000000000 -0500 > @@ -0,0 +1,152 @@ > +/* > + * pci-error.c > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > + > +#include > +#include > +#include > + > +#undef DEBUG > + > +/** Overview: > + * PEH, or "PCI Error Handling" is a PCI bridge technology for > + * dealing with PCI bus errors that can't be dealt with within the > + * usual PCI framework, except by check-stopping the CPU. Systems > + * that are designed for high-availability/reliability cannot afford > + * to crash due to a "mere" PCI error, thus the need for PEH. > + * An PEH-capable bridge operates by converting a detected error > + * into a "slot freeze", taking the PCI adapter off-line, making > + * the slot behave, from the OS'es point of view, as if the slot > + * were "empty": all reads return 0xff's and all writes are silently > + * ignored. PEH slot isolation events can be triggered by parity > + * errors on the address or data busses (e.g. during posted writes), > + * which in turn might be caused by low voltage on the bus, dust, > + * vibration, humidity, radioactivity or plain-old failed hardware. > + * > + * Note, however, that one of the leading causes of PEH slot > + * freeze events are buggy device drivers, buggy device microcode, > + * or buggy device hardware. This is because any attempt by the > + * device to bus-master data to a memory address that is not > + * assigned to the device will trigger a slot freeze. (The idea > + * is to prevent devices-gone-wild from corrupting system memory). > + * Buggy hardware/drivers will have a miserable time co-existing > + * with PEH. > + */ > + > +/* PEH event workqueue setup. */ > +static spinlock_t peh_eventlist_lock = SPIN_LOCK_UNLOCKED; > +LIST_HEAD(peh_eventlist); > +static void peh_event_handler(void *); > +DECLARE_WORK(peh_event_wq, peh_event_handler, NULL); > + > +static struct notifier_block *peh_notifier_chain; > + > +/** > + * peh_event_handler - dispatch PEH events. The detection of a frozen > + * slot can occur inside an interrupt, where it can be hard to do > + * anything about it. The goal of this routine is to pull these > + * detection events out of the context of the interrupt handler, and > + * re-dispatch them for processing at a later time in a normal context. > + * > + * @dummy - unused > + */ > +static void peh_event_handler(void *dummy) > +{ > + unsigned long flags; > + struct peh_event *event; > + > + while (1) { > + spin_lock_irqsave(&peh_eventlist_lock, flags); > + event = NULL; > + if (!list_empty(&peh_eventlist)) { > + event = list_entry(peh_eventlist.next, struct peh_event, list); > + list_del(&event->list); > + } > + spin_unlock_irqrestore(&peh_eventlist_lock, flags); > + if (event == NULL) > + break; > + > + printk(KERN_INFO "PEH: Detected PCI bus error on device " > + "%s %s\n", > + pci_name(event->dev), pci_pretty_name(event->dev)); > + > + notifier_call_chain (&peh_notifier_chain, > + PEH_NOTIFY_ERROR, event); > + > + pci_dev_put(event->dev); > + kfree(event); > + } > +} > + > + > +/** > + * peh_send_failure_event - generate a PCI error event > + * @dev pci device > + * > + * This routine builds a PCI error event which will be delivered > + * to all listeners on the peh_notifier_chain. > + * > + * This routine can be called within an interrupt context; > + * the actual event will be delivered in a normal context > + * (from a workqueue). > + */ > +int peh_send_failure_event (struct pci_dev *dev, > + enum pci_channel_state state, > + int time_unavail) > +{ > + unsigned long flags; > + struct peh_event *event; > + > + event = kmalloc(sizeof(*event), GFP_ATOMIC); > + if (event == NULL) { > + printk (KERN_ERR "PEH: out of memory, event not handled\n"); > + return 1; > + } > + > + event->dev = dev; > + event->state = state; > + event->time_unavail = time_unavail; > + > + /* We may or may not be called in an interrupt context */ > + spin_lock_irqsave(&peh_eventlist_lock, flags); > + list_add(&event->list, &peh_eventlist); > + spin_unlock_irqrestore(&peh_eventlist_lock, flags); > + > + schedule_work(&peh_event_wq); > + > + return 0; > +} > + > +/** > + * peh_register_notifier - Register to find out about EEH events. > + * @nb: notifier block to callback on events > + */ > +int peh_register_notifier(struct notifier_block *nb) > +{ > + return notifier_chain_register(&peh_notifier_chain, nb); > +} > + > +/** > + * peh_unregister_notifier - Unregister to an EEH event notifier. > + * @nb: notifier block to callback on events > + */ > +int peh_unregister_notifier(struct notifier_block *nb) > +{ > + return notifier_chain_unregister(&peh_notifier_chain, nb); > +} > + > +/********************** END OF FILE ******************************/ > --- drivers/scsi/ipr.c.linas-orig 2005-04-29 20:33:36.000000000 -0500 > +++ drivers/scsi/ipr.c 2005-05-31 15:12:08.000000000 -0500 > @@ -5306,6 +5306,85 @@ static void ipr_initiate_ioa_reset(struc > shutdown_type); > } > > +#ifdef CONFIG_SCSI_IPR_EEH_RECOVERY > + > +/** If the PCI slot is frozen, hold off all i/o > + * activity; then, as soon as the slot is available again, > + * initiate an adapter reset. > + */ > +static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd) > +{ > + list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); > + ipr_cmd->done = ipr_reset_ioa_job; > + return IPR_RC_JOB_RETURN; > +} > + > +/** ipr_eeh_frozen -- called when slot has experience PCI bus error. > + * This routine is called to tell us that the PCI bus is down. > + * Can't do anything here, except put the device driver into a > + * holding pattern, waiting for the PCI bus to come back. > + */ > +static void ipr_eeh_frozen (struct pci_dev *pdev) > +{ > + unsigned long flags = 0; > + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); > + > + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); > + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE); > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); > +} > + > +/** ipr_eeh_slot_reset - called when pci slot has been reset. > + * > + * This routine is called by the pci error recovery recovery > + * code after the PCI slot has been reset, just before we > + * should resume normal operations. > + */ > +static int ipr_eeh_slot_reset (struct pci_dev *pdev) > +{ > + unsigned long flags = 0; > + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); > + > + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); > + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, > + IPR_SHUTDOWN_NONE); > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); > + > + return PCIERR_RESULT_RECOVERED; > +} > + > +/** This routine is called when the PCI bus has permanently > + * failed. This routine should purge all pending I/O and > + * shut down the device driver (close and unload). > + * XXX Needs to be implemented. > + */ > +static void ipr_eeh_perm_failure (struct pci_dev *pdev) > +{ > +#if 0 // XXXXXXXXXXXXXXXXXXXXXXX > + ipr_cmd->job_step = ipr_reset_shutdown_ioa; > + rc = IPR_RC_JOB_CONTINUE; > +#endif > +} > + > +static int ipr_eeh_error_detected (struct pci_dev *pdev, > + enum pci_channel_state state) > +{ > + switch (state) { > + case pci_channel_io_frozen: > + ipr_eeh_frozen (pdev); > + return PCIERR_RESULT_NEED_RESET; > + > + case pci_channel_io_perm_failure: > + ipr_eeh_perm_failure (pdev); > + return PCIERR_RESULT_DISCONNECT; > + break; > + default: > + break; > + } > + return PCIERR_RESULT_NEED_RESET; > +} > +#endif > + > /** > * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) > * @ioa_cfg: ioa cfg struct > @@ -6015,6 +6094,10 @@ static struct pci_driver ipr_driver = { > .id_table = ipr_pci_table, > .probe = ipr_probe, > .remove = ipr_remove, > + .err_handler = { > + .error_detected = ipr_eeh_error_detected, > + .slot_reset = ipr_eeh_slot_reset, > + }, > .driver = { > .shutdown = ipr_shutdown, > }, > --- drivers/scsi/sym53c8xx_2/sym_glue.c.linas-orig 2005-04-29 20:33:12.000000000 -0500 > +++ drivers/scsi/sym53c8xx_2/sym_glue.c 2005-05-31 13:52:55.000000000 -0500 > @@ -770,6 +770,10 @@ static irqreturn_t sym53c8xx_intr(int ir > struct sym_hcb *np = (struct sym_hcb *)dev_id; > > if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("["); > +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY > + if (np->s.io_state != pci_channel_io_normal) > + return IRQ_HANDLED; > +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ > > spin_lock_irqsave(np->s.host->host_lock, flags); > sym_interrupt(np); > @@ -844,6 +848,27 @@ static void sym_eh_done(struct scsi_cmnd > */ > static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } > > +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY > +static void sym_eeh_timeout(u_long p) > +{ > + struct sym_eh_wait *ep = (struct sym_eh_wait *) p; > + if (!ep) > + return; > + complete(&ep->done); > +} > + > +static void sym_eeh_done(struct sym_eh_wait *ep) > +{ > + if (!ep) > + return; > + ep->timed_out = 0; > + if (!del_timer(&ep->timer)) > + return; > + > + complete(&ep->done); > +} > +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ > + > /* > * Generic method for our eh processing. > * The 'op' argument tells what we have to do. > @@ -893,6 +918,37 @@ prepare: > > /* Try to proceed the operation we have been asked for */ > sts = -1; > +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY > + > + /* We may be in an error condition because the PCI bus > + * went down. In this case, we need to wait until the > + * PCI bus is reset, the card is reset, and only then > + * proceed with the scsi error recovery. We'll wait > + * for 15 seconds for this to happen. > + */ > +#define WAIT_FOR_PCI_RECOVERY 15 > + if (np->s.io_state != pci_channel_io_normal) { > + struct sym_eh_wait eeh, *eep = &eeh; > + np->s.io_reset_wait = eep; > + init_completion(&eep->done); > + init_timer(&eep->timer); > + eep->to_do = SYM_EH_DO_WAIT; > + eep->timer.expires = jiffies + (WAIT_FOR_PCI_RECOVERY*HZ); > + eep->timer.function = sym_eeh_timeout; > + eep->timer.data = (u_long)eep; > + eep->timed_out = 1; /* Be pessimistic for once :) */ > + add_timer(&eep->timer); > + spin_unlock_irq(np->s.host->host_lock); > + wait_for_completion(&eep->done); > + spin_lock_irq(np->s.host->host_lock); > + if (eep->timed_out) { > + printk (KERN_ERR "%s: Timed out waiting for PCI reset\n", > + sym_name(np)); > + } > + np->s.io_reset_wait = NULL; > + } > +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ > + > switch(op) { > case SYM_EH_ABORT: > sts = sym_abort_scsiio(np, cmd, 1); > @@ -1625,6 +1681,8 @@ static struct Scsi_Host * __devinit sym_ > if (!np) > goto attach_failed; > np->s.device = dev->pdev; > + np->s.io_state = pci_channel_io_normal; > + np->s.io_reset_wait = NULL; > np->bus_dmat = dev->pdev; /* Result in 1 DMA pool per HBA */ > host_data->ncb = np; > np->s.host = instance; > @@ -2048,6 +2106,59 @@ static int sym_detach(struct sym_hcb *np > return 1; > } > > +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY > +/** sym2_io_error_detected() is called when PCI error is detected */ > +int sym2_io_error_detected (struct pci_dev *pdev, enum pci_channel_state state) > +{ > + struct sym_hcb *np = pci_get_drvdata(pdev); > + > + np->s.io_state = state; > + // XXX If slot is permanently frozen, then what? > + // Should we scsi_remove_host() maybe ?? > + > + /* Request a slot slot reset. */ > + return PCIERR_RESULT_NEED_RESET; > +} > + > +/** sym2_io_slot_reset is called when the pci bus has been reset. > + * Restart the card from scratch. */ > +int sym2_io_slot_reset (struct pci_dev *pdev) > +{ > + struct sym_hcb *np = pci_get_drvdata(pdev); > + > + msleep (500); // pure paranoia -- wait for device to settle > + printk (KERN_INFO "%s: recovering from a PCI slot reset\n", > + sym_name(np)); > + > + if (pci_enable_device(pdev)) > + printk (KERN_ERR "%s: device setup failed most egregiously\n", > + sym_name(np)); > + > + pci_set_master(pdev); > + > + /* Perform host reset only on one instance of the card */ > + if (0 == PCI_FUNC (pdev->devfn)) > + sym_reset_scsi_bus(np, 0); > + > + return PCIERR_RESULT_RECOVERED; > +} > + > +/** sym2_io_resume is called when the error recovery driver > + * tells us that its OK to resume normal operation. > + */ > +void sym2_io_resume (struct pci_dev *pdev) > +{ > + struct sym_hcb *np = pci_get_drvdata(pdev); > + > + /* Perform device startup only once for this card. */ > + if (0 == PCI_FUNC (pdev->devfn)) > + sym_start_up (np, 1); > + > + np->s.io_state = pci_channel_io_normal; > + sym_eeh_done (np->s.io_reset_wait); > +} > +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ > + > /* > * Driver host template. > */ > @@ -2359,6 +2470,11 @@ static struct pci_driver sym2_driver = { > .id_table = sym2_id_table, > .probe = sym2_probe, > .remove = __devexit_p(sym2_remove), > + .err_handler = { > + .error_detected = sym2_io_error_detected, > + .slot_reset = sym2_io_slot_reset, > + .resume = sym2_io_resume, > + }, > }; > > static int __init sym2_init(void) > --- drivers/scsi/sym53c8xx_2/sym_glue.h.linas-orig 2005-04-29 20:32:45.000000000 -0500 > +++ drivers/scsi/sym53c8xx_2/sym_glue.h 2005-05-06 16:29:39.000000000 -0500 > @@ -358,6 +358,10 @@ struct sym_shcb { > char chip_name[8]; > struct pci_dev *device; > > + /* pci bus i/o state; waiter for clearing of i/o state */ > + enum pci_channel_state io_state; > + struct sym_eh_wait *io_reset_wait; > + > struct Scsi_Host *host; > > void __iomem * mmio_va; /* MMIO kernel virtual address */ > --- drivers/scsi/sym53c8xx_2/sym_hipd.c.linas-orig 2005-04-29 20:22:45.000000000 -0500 > +++ drivers/scsi/sym53c8xx_2/sym_hipd.c 2005-05-20 15:40:43.000000000 -0500 > @@ -2836,6 +2836,7 @@ void sym_interrupt (struct sym_hcb *np) > u_char istat, istatc; > u_char dstat; > u_short sist; > + u_int icnt; > > /* > * interrupt on the fly ? > @@ -2877,6 +2878,7 @@ void sym_interrupt (struct sym_hcb *np) > sist = 0; > dstat = 0; > istatc = istat; > + icnt = 0; > do { > if (istatc & SIP) > sist |= INW (nc_sist); > @@ -2884,6 +2886,14 @@ void sym_interrupt (struct sym_hcb *np) > dstat |= INB (nc_dstat); > istatc = INB (nc_istat); > istat |= istatc; > +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY > + /* Prevent deadlock waiting on a condition that may never clear. */ > + icnt ++; > + if (100 < icnt) { > + if (eeh_slot_is_isolated(np->s.device)) > + return; > + } > +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ > } while (istatc & (SIP|DIP)); > > if (DEBUG_FLAGS & DEBUG_TINY) > --- drivers/scsi/Kconfig.linas-orig 2005-04-29 20:31:30.000000000 -0500 > +++ drivers/scsi/Kconfig 2005-05-24 11:17:40.000000000 -0500 > @@ -1032,6 +1032,14 @@ config SCSI_SYM53C8XX_IOMAPPED > the card. This is significantly slower then using memory > mapped IO. Most people should answer N. > > +config SCSI_SYM53C8XX_EEH_RECOVERY > + bool "Enable PCI bus error recovery" > + depends on SCSI_SYM53C8XX_2 && PPC_PSERIES > + help > + If you say Y here, the driver will be able to recover from > + PCI bus errors on many PowerPC platforms. IBM pSeries users > + should answer Y. > + > config SCSI_IPR > tristate "IBM Power Linux RAID adapter support" > depends on PCI && SCSI > @@ -1057,6 +1065,14 @@ config SCSI_IPR_DUMP > If you enable this support, the iprdump daemon can be used > to capture adapter failure analysis information. > > +config SCSI_IPR_EEH_RECOVERY > + bool "Enable PCI bus error recovery" > + depends on SCSI_IPR && PPC_PSERIES > + help > + If you say Y here, the driver will be able to recover from > + PCI bus errors on many PowerPC platforms. IBM pSeries users > + should answer Y. > + > config SCSI_ZALON > tristate "Zalon SCSI support" > depends on GSC && SCSI > --- arch/ppc64/defconfig.linas-orig 2005-05-20 12:16:19.000000000 -0500 > +++ arch/ppc64/defconfig 2005-05-20 12:16:58.000000000 -0500 > @@ -255,6 +255,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MOD > CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 > CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 > # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set > +CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y > # CONFIG_SCSI_QLOGIC_ISP is not set > # CONFIG_SCSI_QLOGIC_FC is not set > # CONFIG_SCSI_QLOGIC_1280 is not set > --- arch/ppc64/configs/pSeries_defconfig.linas-orig 2005-04-29 20:34:04.000000000 -0500 > +++ arch/ppc64/configs/pSeries_defconfig 2005-05-24 11:18:45.000000000 -0500 > @@ -275,9 +275,11 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MOD > CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 > CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 > # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set > +CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y > CONFIG_SCSI_IPR=y > # CONFIG_SCSI_IPR_TRACE is not set > # CONFIG_SCSI_IPR_DUMP is not set > +CONFIG_SCSI_IPR_EEH_RECOVERY=y > # CONFIG_SCSI_QLOGIC_ISP is not set > # CONFIG_SCSI_QLOGIC_FC is not set > # CONFIG_SCSI_QLOGIC_1280 is not set > --- include/asm-ppc64/eeh.h.linas-orig 2005-04-29 20:34:03.000000000 -0500 > +++ include/asm-ppc64/eeh.h 2005-05-31 13:55:18.000000000 -0500 > @@ -1,4 +1,4 @@ > -/* > +/* > * eeh.h > * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. > * > @@ -6,12 +6,12 @@ > * it under the terms of the GNU General Public License as published by > * the Free Software Foundation; either version 2 of the License, or > * (at your option) any later version. > - * > + * > * This program is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > * GNU General Public License for more details. > - * > + * > * You should have received a copy of the GNU General Public License > * along with this program; if not, write to the Free Software > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > @@ -23,6 +23,7 @@ > #include > #include > #include > +#include > #include > > struct pci_dev; > @@ -36,6 +37,11 @@ struct notifier_block; > #define EEH_MODE_SUPPORTED (1<<0) > #define EEH_MODE_NOCHECK (1<<1) > #define EEH_MODE_ISOLATED (1<<2) > +#define EEH_MODE_RECOVERING (1<<3) > + > +/* Max number of EEH freezes allowed before we consider the device > + * to be permanently disabled. */ > +#define EEH_MAX_ALLOWED_FREEZES 5 > > void __init eeh_init(void); > unsigned long eeh_check_failure(const volatile void __iomem *token, > @@ -59,35 +65,82 @@ void eeh_add_device_late(struct pci_dev > * eeh_remove_device - undo EEH setup for the indicated pci device > * @dev: pci device to be removed > * > - * This routine should be when a device is removed from a running > - * system (e.g. by hotplug or dlpar). > + * This routine should be called when a device is removed from > + * a running system (e.g. by hotplug or dlpar). It unregisters > + * the PCI device from the EEH subsystem. I/O errors affecting > + * this device will no longer be detected after this call; thus, > + * i/o errors affecting this slot may leave this device unusable. > */ > void eeh_remove_device(struct pci_dev *); > > -#define EEH_DISABLE 0 > -#define EEH_ENABLE 1 > -#define EEH_RELEASE_LOADSTORE 2 > -#define EEH_RELEASE_DMA 3 > +/** > + * eeh_slot_is_isolated -- return non-zero value if slot is frozen > + */ > +int eeh_slot_is_isolated (struct pci_dev *dev); > > /** > - * Notifier event flags. > + * eeh_ioaddr_is_isolated -- return non-zero value if device at > + * io address is frozen. > */ > -#define EEH_NOTIFY_FREEZE 1 > +int eeh_ioaddr_is_isolated(const volatile void __iomem *token); > > -/** EEH event -- structure holding pci slot data that describes > - * a change in the isolation status of a PCI slot. A pointer > - * to this struct is passed as the data pointer in a notify callback. > - */ > -struct eeh_event { > - struct list_head list; > - struct pci_dev *dev; > - struct device_node *dn; > - int reset_state; > -}; > - > -/** Register to find out about EEH events. */ > -int eeh_register_notifier(struct notifier_block *nb); > -int eeh_unregister_notifier(struct notifier_block *nb); > +/** > + * eeh_slot_error_detail -- record and EEH error condition to the log > + * @severity: 1 if temporary, 2 if permanent failure. > + * > + * Obtains the the EEH error details from the RTAS subsystem, > + * and then logs these details with the RTAS error log system. > + */ > +void eeh_slot_error_detail (struct device_node *dn, int severity); > + > +/** > + * rtas_set_slot_reset -- unfreeze a frozen slot > + * > + * Clear the EEH-frozen condition on a slot. This routine > + * does this by asserting the PCI #RST line for 1/8th of > + * a second; this routine will sleep while the adapter is > + * being reset. > + */ > +void rtas_set_slot_reset (struct device_node *dn); > + > +/** rtas_pci_slot_reset raises/lowers the pci #RST line > + * state: 1/0 to raise/lower the #RST > + * > + * Clear the EEH-frozen condition on a slot. This routine > + * asserts the PCI #RST line if the 'state' argument is '1', > + * and drops the #RST line if 'state is '0'. This routine is > + * safe to call in an interrupt context. > + * > + */ > +void rtas_pci_slot_reset(struct device_node *dn, int state); > +void eeh_pci_slot_reset(struct pci_dev *dev, int state); > + > +/** eeh_pci_slot_availability -- Indicates whether a PCI > + * slot is ready to be used. After a PCI reset, it may take a while > + * for the PCI fabric to fully reset the comminucations path to the > + * given PCI card. This routine can be used to determine how long > + * to wait before a PCI slot might become usable. > + * > + * This routine returns how long to wait (in milliseconds) before > + * the slot is expected to be usable. A value of zero means the > + * slot is immediately usable. A negavitve value means that the > + * slot is permanently disabled. > + */ > +int eeh_pci_slot_availability(struct pci_dev *dev); > + > +/** Restore device configuration info across device resets. > + */ > +void eeh_restore_bars(struct device_node *); > +void eeh_pci_restore_bars(struct pci_dev *dev); > + > +/** > + * rtas_configure_bridge -- firmware initialization of pci bridge > + * > + * Ask the firmware to configure any PCI bridge devices > + * located behind the indicated node. Required after a > + * pci device reset. > + */ > +void rtas_configure_bridge(struct device_node *dn); > > /** > * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. > @@ -116,7 +169,7 @@ int eeh_unregister_notifier(struct notif > #define EEH_IO_ERROR_VALUE(size) (-1UL) > #endif > > -/* > +/* > * MMIO read/write operations with EEH support. > */ > static inline u8 eeh_readb(const volatile void __iomem *addr) > @@ -238,21 +291,21 @@ static inline void eeh_memcpy_fromio(voi > *((u8 *)dest) = *((volatile u8 *)vsrc); > __asm__ __volatile__ ("eieio" : : : "memory"); > vsrc = (void *)((unsigned long)vsrc + 1); > - dest = (void *)((unsigned long)dest + 1); > + dest = (void *)((unsigned long)dest + 1); > n--; > } > while(n > 4) { > *((u32 *)dest) = *((volatile u32 *)vsrc); > __asm__ __volatile__ ("eieio" : : : "memory"); > vsrc = (void *)((unsigned long)vsrc + 4); > - dest = (void *)((unsigned long)dest + 4); > + dest = (void *)((unsigned long)dest + 4); > n -= 4; > } > while(n) { > *((u8 *)dest) = *((volatile u8 *)vsrc); > __asm__ __volatile__ ("eieio" : : : "memory"); > vsrc = (void *)((unsigned long)vsrc + 1); > - dest = (void *)((unsigned long)dest + 1); > + dest = (void *)((unsigned long)dest + 1); > n--; > } > __asm__ __volatile__ ("sync" : : : "memory"); > @@ -274,19 +327,19 @@ static inline void eeh_memcpy_toio(volat > while(n && (!EEH_CHECK_ALIGN(vdest, 4) || !EEH_CHECK_ALIGN(src, 4))) { > *((volatile u8 *)vdest) = *((u8 *)src); > src = (void *)((unsigned long)src + 1); > - vdest = (void *)((unsigned long)vdest + 1); > + vdest = (void *)((unsigned long)vdest + 1); > n--; > } > while(n > 4) { > *((volatile u32 *)vdest) = *((volatile u32 *)src); > src = (void *)((unsigned long)src + 4); > - vdest = (void *)((unsigned long)vdest + 4); > + vdest = (void *)((unsigned long)vdest + 4); > n-=4; > } > while(n) { > *((volatile u8 *)vdest) = *((u8 *)src); > src = (void *)((unsigned long)src + 1); > - vdest = (void *)((unsigned long)vdest + 1); > + vdest = (void *)((unsigned long)vdest + 1); > n--; > } > __asm__ __volatile__ ("sync" : : : "memory"); > --- include/asm-ppc64/prom.h.linas-orig 2005-04-29 20:32:46.000000000 -0500 > +++ include/asm-ppc64/prom.h 2005-05-06 12:28:43.000000000 -0500 > @@ -119,6 +119,7 @@ struct property { > */ > struct pci_controller; > struct iommu_table; > +struct eeh_recovery_ops; > > struct device_node { > char *name; > @@ -137,8 +138,12 @@ struct device_node { > int devfn; /* for pci devices */ > int eeh_mode; /* See eeh.h for possible EEH_MODEs */ > int eeh_config_addr; > + int eeh_check_count; /* number of times device driver ignored error */ > + int eeh_freeze_count; /* number of times this device froze up. */ > + int eeh_is_bridge; /* device is pci-to-pci bridge */ > struct pci_controller *phb; /* for pci devices */ > struct iommu_table *iommu_table; /* for phb's or bridges */ > + u32 config_space[16]; /* saved PCI config space */ > > struct property *properties; > struct device_node *parent; > --- include/asm-ppc64/rtas.h.linas-orig 2005-04-29 20:32:32.000000000 -0500 > +++ include/asm-ppc64/rtas.h 2005-05-06 12:28:43.000000000 -0500 > @@ -243,4 +243,6 @@ extern unsigned long rtas_rmo_buf; > > #define GLOBAL_INTERRUPT_QUEUE 9005 > > +extern int rtas_write_config(struct device_node *dn, int where, int size, u32 val); > + > #endif /* _PPC64_RTAS_H */ > --- arch/ppc64/kernel/eeh.c.linas-orig 2005-04-29 20:29:19.000000000 -0500 > +++ arch/ppc64/kernel/eeh.c 2005-05-31 15:13:51.000000000 -0500 > @@ -1,32 +1,33 @@ > /* > * eeh.c > * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation > - * > + * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > * the Free Software Foundation; either version 2 of the License, or > * (at your option) any later version. > - * > + * > * This program is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > * GNU General Public License for more details. > - * > + * > * You should have received a copy of the GNU General Public License > * along with this program; if not, write to the Free Software > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > > -#include > +#include > #include > +#include > #include > -#include > #include > #include > #include > #include > #include > #include > +#include > #include > #include > #include > @@ -49,8 +50,8 @@ > * were "empty": all reads return 0xff's and all writes are silently > * ignored. EEH slot isolation events can be triggered by parity > * errors on the address or data busses (e.g. during posted writes), > - * which in turn might be caused by dust, vibration, humidity, > - * radioactivity or plain-old failed hardware. > + * which in turn might be caused by low voltage on the bus, dust, > + * vibration, humidity, radioactivity or plain-old failed hardware. > * > * Note, however, that one of the leading causes of EEH slot > * freeze events are buggy device drivers, buggy device microcode, > @@ -75,22 +76,13 @@ > #define BUID_HI(buid) ((buid) >> 32) > #define BUID_LO(buid) ((buid) & 0xffffffff) > > -/* EEH event workqueue setup. */ > -static DEFINE_SPINLOCK(eeh_eventlist_lock); > -LIST_HEAD(eeh_eventlist); > -static void eeh_event_handler(void *); > -DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL); > - > -static struct notifier_block *eeh_notifier_chain; > - > /* > * If a device driver keeps reading an MMIO register in an interrupt > * handler after a slot isolation event has occurred, we assume it > * is broken and panic. This sets the threshold for how many read > * attempts we allow before panicking. > */ > -#define EEH_MAX_FAILS 1000 > -static atomic_t eeh_fail_count; > +#define EEH_MAX_FAILS 100000 > > /* RTAS tokens */ > static int ibm_set_eeh_option; > @@ -107,6 +99,10 @@ static DEFINE_SPINLOCK(slot_errbuf_lock) > static int eeh_error_buf_size; > > /* System monitoring statistics */ > +static DEFINE_PER_CPU(unsigned long, no_device); > +static DEFINE_PER_CPU(unsigned long, no_dn); > +static DEFINE_PER_CPU(unsigned long, no_cfg_addr); > +static DEFINE_PER_CPU(unsigned long, ignored_check); > static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); > static DEFINE_PER_CPU(unsigned long, false_positives); > static DEFINE_PER_CPU(unsigned long, ignored_failures); > @@ -225,9 +221,9 @@ pci_addr_cache_insert(struct pci_dev *de > while (*p) { > parent = *p; > piar = rb_entry(parent, struct pci_io_addr_range, rb_node); > - if (alo < piar->addr_lo) { > + if (ahi < piar->addr_lo) { > p = &parent->rb_left; > - } else if (ahi > piar->addr_hi) { > + } else if (alo > piar->addr_hi) { > p = &parent->rb_right; > } else { > if (dev != piar->pcidev || > @@ -246,6 +242,11 @@ pci_addr_cache_insert(struct pci_dev *de > piar->pcidev = dev; > piar->flags = flags; > > +#ifdef DEBUG > + printk (KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", > + alo, ahi, pci_name (dev)); > +#endif > + > rb_link_node(&piar->rb_node, parent, p); > rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); > > @@ -268,9 +269,10 @@ static void __pci_addr_cache_insert_devi > /* Skip any devices for which EEH is not enabled. */ > if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || > dn->eeh_mode & EEH_MODE_NOCHECK) { > -#ifdef DEBUG > - printk(KERN_INFO "PCI: skip building address cache for=%s %s\n", > - pci_name(dev), pci_pretty_name(dev)); > +// #ifdef DEBUG > +#if 1 > + printk(KERN_INFO "PCI: skip building address cache for=%s %s %s\n", > + pci_name(dev), pci_pretty_name(dev), dn->type); > #endif > return; > } > @@ -369,8 +371,12 @@ void pci_addr_cache_remove_device(struct > */ > void __init pci_addr_cache_build(void) > { > + struct device_node *dn; > struct pci_dev *dev = NULL; > > + if (!eeh_subsystem_enabled) > + return; > + > spin_lock_init(&pci_io_addr_cache_root.piar_lock); > > while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { > @@ -379,6 +385,17 @@ void __init pci_addr_cache_build(void) > continue; > } > pci_addr_cache_insert_device(dev); > + > + /* Save the BAR's; firmware doesn't restore these after EEH reset */ > + dn = pci_device_to_OF_node(dev); > + if (dn) { > + int i; > + for (i = 0; i < 16; i++) > + pci_read_config_dword(dev, i * 4, &dn->config_space[i]); > + > + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) > + dn->eeh_is_bridge = 1; > + } > } > > #ifdef DEBUG > @@ -390,24 +407,32 @@ void __init pci_addr_cache_build(void) > /* --------------------------------------------------------------- */ > /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */ > > -/** > - * eeh_register_notifier - Register to find out about EEH events. > - * @nb: notifier block to callback on events > - */ > -int eeh_register_notifier(struct notifier_block *nb) > +void eeh_slot_error_detail (struct device_node *dn, int severity) > { > - return notifier_chain_register(&eeh_notifier_chain, nb); > -} > + unsigned long flags; > + int rc; > > -/** > - * eeh_unregister_notifier - Unregister to an EEH event notifier. > - * @nb: notifier block to callback on events > - */ > -int eeh_unregister_notifier(struct notifier_block *nb) > -{ > - return notifier_chain_unregister(&eeh_notifier_chain, nb); > + if (!dn) return; > + > + /* Log the error with the rtas logger */ > + spin_lock_irqsave(&slot_errbuf_lock, flags); > + memset(slot_errbuf, 0, eeh_error_buf_size); > + > + rc = rtas_call(ibm_slot_error_detail, > + 8, 1, NULL, dn->eeh_config_addr, > + BUID_HI(dn->phb->buid), > + BUID_LO(dn->phb->buid), NULL, 0, > + virt_to_phys(slot_errbuf), > + eeh_error_buf_size, > + severity); > + > + if (rc == 0) > + log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); > + spin_unlock_irqrestore(&slot_errbuf_lock, flags); > } > > +EXPORT_SYMBOL(eeh_slot_error_detail); > + > /** > * read_slot_reset_state - Read the reset state of a device node's slot > * @dn: device node to read > @@ -422,6 +447,7 @@ static int read_slot_reset_state(struct > outputs = 4; > } else { > token = ibm_read_slot_reset_state; > + rets[2] = 0; /* fake PE Unavailable info */ > outputs = 3; > } > > @@ -430,75 +456,8 @@ static int read_slot_reset_state(struct > } > > /** > - * eeh_panic - call panic() for an eeh event that cannot be handled. > - * The philosophy of this routine is that it is better to panic and > - * halt the OS than it is to risk possible data corruption by > - * oblivious device drivers that don't know better. > - * > - * @dev pci device that had an eeh event > - * @reset_state current reset state of the device slot > - */ > -static void eeh_panic(struct pci_dev *dev, int reset_state) > -{ > - /* > - * XXX We should create a separate sysctl for this. > - * > - * Since the panic_on_oops sysctl is used to halt the system > - * in light of potential corruption, we can use it here. > - */ > - if (panic_on_oops) > - panic("EEH: MMIO failure (%d) on device:%s %s\n", reset_state, > - pci_name(dev), pci_pretty_name(dev)); > - else { > - __get_cpu_var(ignored_failures)++; > - printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s %s\n", > - reset_state, pci_name(dev), pci_pretty_name(dev)); > - } > -} > - > -/** > - * eeh_event_handler - dispatch EEH events. The detection of a frozen > - * slot can occur inside an interrupt, where it can be hard to do > - * anything about it. The goal of this routine is to pull these > - * detection events out of the context of the interrupt handler, and > - * re-dispatch them for processing at a later time in a normal context. > - * > - * @dummy - unused > - */ > -static void eeh_event_handler(void *dummy) > -{ > - unsigned long flags; > - struct eeh_event *event; > - > - while (1) { > - spin_lock_irqsave(&eeh_eventlist_lock, flags); > - event = NULL; > - if (!list_empty(&eeh_eventlist)) { > - event = list_entry(eeh_eventlist.next, struct eeh_event, list); > - list_del(&event->list); > - } > - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); > - if (event == NULL) > - break; > - > - printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device " > - "%s %s\n", event->reset_state, > - pci_name(event->dev), pci_pretty_name(event->dev)); > - > - atomic_set(&eeh_fail_count, 0); > - notifier_call_chain (&eeh_notifier_chain, > - EEH_NOTIFY_FREEZE, event); > - > - __get_cpu_var(slot_resets)++; > - > - pci_dev_put(event->dev); > - kfree(event); > - } > -} > - > -/** > - * eeh_token_to_phys - convert EEH address token to phys address > - * @token i/o token, should be address in the form 0xE.... > + * eeh_token_to_phys - convert I/O address to phys address > + * @token i/o address, should be address in the form 0xA.... > */ > static inline unsigned long eeh_token_to_phys(unsigned long token) > { > @@ -513,6 +472,18 @@ static inline unsigned long eeh_token_to > return pa | (token & (PAGE_SIZE-1)); > } > > + > +static inline struct pci_dev * eeh_find_pci_dev(struct device_node *dn) > +{ > + struct pci_dev *dev = NULL; > + for_each_pci_dev(dev) { > + if (pci_device_to_OF_node(dev) == dn) > + return dev; > + } > + return NULL; > +} > + > + > /** > * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze > * @dn device node > @@ -528,29 +499,37 @@ static inline unsigned long eeh_token_to > * > * It is safe to call this routine in an interrupt context. > */ > +extern void disable_irq_nosync(unsigned int); > + > int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) > { > int ret; > int rets[3]; > - unsigned long flags; > - int rc, reset_state; > - struct eeh_event *event; > + enum pci_channel_state state; > > __get_cpu_var(total_mmio_ffs)++; > > if (!eeh_subsystem_enabled) > return 0; > > - if (!dn) > + if (!dn) { > + __get_cpu_var(no_dn)++; > return 0; > + } > > /* Access to IO BARs might get this far and still not want checking. */ > if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || > dn->eeh_mode & EEH_MODE_NOCHECK) { > + __get_cpu_var(ignored_check)++; > +#ifdef DEBUG > + printk ("EEH:ignored check for %s %s\n", > + pci_pretty_name (dev), dn->full_name); > +#endif > return 0; > } > > if (!dn->eeh_config_addr) { > + __get_cpu_var(no_cfg_addr)++; > return 0; > } > > @@ -559,12 +538,18 @@ int eeh_dn_check_failure(struct device_n > * slot, we know it's bad already, we don't need to check... > */ > if (dn->eeh_mode & EEH_MODE_ISOLATED) { > - atomic_inc(&eeh_fail_count); > - if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) { > + dn->eeh_check_count ++; > + if (dn->eeh_check_count >= EEH_MAX_FAILS) { > + printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n", > + dn->eeh_check_count); > + dump_stack(); > /* re-read the slot reset state */ > if (read_slot_reset_state(dn, rets) != 0) > rets[0] = -1; /* reset state unknown */ > - eeh_panic(dev, rets[0]); > + > + /* If we are here, then we hit an infinite loop. Stop. */ > + panic("EEH: MMIO halt (%d) on device:%s %s\n", rets[0], > + pci_name(dev), pci_pretty_name(dev)); > } > return 0; > } > @@ -577,53 +562,41 @@ int eeh_dn_check_failure(struct device_n > * In any case they must share a common PHB. > */ > ret = read_slot_reset_state(dn, rets); > - if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) { > + if (!(ret == 0 && ((rets[1] == 1 && (rets[0] == 2 || rets[0] >= 4)) > + || (rets[0] == 5)))) { > __get_cpu_var(false_positives)++; > return 0; > } > > - /* prevent repeated reports of this failure */ > - dn->eeh_mode |= EEH_MODE_ISOLATED; > - > - reset_state = rets[0]; > + /* Note that empty slots will fail; empty slots don't have children... */ > + if ((rets[0] == 5) && (dn->child == NULL)) { > + __get_cpu_var(false_positives)++; > + return 0; > + } > > - spin_lock_irqsave(&slot_errbuf_lock, flags); > - memset(slot_errbuf, 0, eeh_error_buf_size); > + /* Prevent repeated reports of this failure */ > + dn->eeh_mode |= EEH_MODE_ISOLATED; > + __get_cpu_var(slot_resets)++; > > - rc = rtas_call(ibm_slot_error_detail, > - 8, 1, NULL, dn->eeh_config_addr, > - BUID_HI(dn->phb->buid), > - BUID_LO(dn->phb->buid), NULL, 0, > - virt_to_phys(slot_errbuf), > - eeh_error_buf_size, > - 1 /* Temporary Error */); > + if (!dev) > + dev = eeh_find_pci_dev (dn); > > - if (rc == 0) > - log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); > - spin_unlock_irqrestore(&slot_errbuf_lock, flags); > + /* Some devices go crazy if irq's are not ack'ed; disable irq now */ > + if (dev) > + disable_irq_nosync (dev->irq); > + > + state = pci_channel_io_normal; > + if ((rets[0] == 2) || (rets[0] == 4)) > + state = pci_channel_io_frozen; > + if (rets[0] == 5) > + state = pci_channel_io_perm_failure; > > - printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", > - rets[0], dn->name, dn->full_name); > - event = kmalloc(sizeof(*event), GFP_ATOMIC); > - if (event == NULL) { > - eeh_panic(dev, reset_state); > - return 1; > - } > - > - event->dev = dev; > - event->dn = dn; > - event->reset_state = reset_state; > - > - /* We may or may not be called in an interrupt context */ > - spin_lock_irqsave(&eeh_eventlist_lock, flags); > - list_add(&event->list, &eeh_eventlist); > - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); > + peh_send_failure_event (dev, state, rets[2]); > > /* Most EEH events are due to device driver bugs. Having > * a stack trace will help the device-driver authors figure > * out what happened. So print that out. */ > - dump_stack(); > - schedule_work(&eeh_event_wq); > + if (rets[0] != 5) dump_stack(); > > return 0; > } > @@ -635,7 +608,6 @@ EXPORT_SYMBOL(eeh_dn_check_failure); > * @token i/o token, should be address in the form 0xA.... > * @val value, should be all 1's (XXX why do we need this arg??) > * > - * Check for an eeh failure at the given token address. > * Check for an EEH failure at the given token address. Call this > * routine if the result of a read was all 0xff's and you want to > * find out if this is due to an EEH slot freeze event. This routine > @@ -643,6 +615,7 @@ EXPORT_SYMBOL(eeh_dn_check_failure); > * > * Note this routine is safe to call in an interrupt context. > */ > + > unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) > { > unsigned long addr; > @@ -652,8 +625,10 @@ unsigned long eeh_check_failure(const vo > /* Finding the phys addr + pci device; this is pretty quick. */ > addr = eeh_token_to_phys((unsigned long __force) token); > dev = pci_get_device_by_addr(addr); > - if (!dev) > + if (!dev) { > + __get_cpu_var(no_device)++; > return val; > + } > > dn = pci_device_to_OF_node(dev); > eeh_dn_check_failure (dn, dev); > @@ -664,6 +639,234 @@ unsigned long eeh_check_failure(const vo > > EXPORT_SYMBOL(eeh_check_failure); > > +/* ------------------------------------------------------------- */ > +/* The code below deals with error recovery */ > + > +int > +eeh_slot_is_isolated(struct pci_dev *dev) > +{ > + struct device_node *dn; > + dn = pci_device_to_OF_node(dev); > + return (dn->eeh_mode & EEH_MODE_ISOLATED); > +} > +EXPORT_SYMBOL(eeh_slot_is_isolated); > + > +int > +eeh_ioaddr_is_isolated(const volatile void __iomem *token) > +{ > + unsigned long addr; > + struct pci_dev *dev; > + int rc; > + > + addr = eeh_token_to_phys((unsigned long __force) token); > + dev = pci_get_device_by_addr(addr); > + if (!dev) > + return 0; > + rc = eeh_slot_is_isolated(dev); > + pci_dev_put(dev); > + return rc; > +} > + > +/** eeh_pci_slot_reset -- raises/lowers the pci #RST line > + * state: 1/0 to raise/lower the #RST > + */ > +void > +eeh_pci_slot_reset(struct pci_dev *dev, int state) > +{ > + struct device_node *dn = pci_device_to_OF_node(dev); > + rtas_pci_slot_reset (dn, state); > +} > + > +/** Return negative value if a permanent error, else return > + * a number of milliseconds to wait until the PCI slot is > + * ready to be used. > + */ > +static int > +eeh_slot_availability(struct device_node *dn) > +{ > + int rc; > + int rets[3]; > + > + rc = read_slot_reset_state(dn, rets); > + > + if (rc) return rc; > + > + if (rets[1] == 0) return -1; /* EEH is not supported */ > + if (rets[0] == 0) return 0; /* Oll Korrect */ > + if (rets[0] == 5) { > + if (rets[2] == 0) return -1; /* permanently unavailable */ > + return rets[2]; /* number of millisecs to wait */ > + } > + return -1; > +} > + > +int > +eeh_pci_slot_availability(struct pci_dev *dev) > +{ > + struct device_node *dn = pci_device_to_OF_node(dev); > + if (!dn) return -1; > + > + BUG_ON (dn->phb==NULL); > + if (dn->phb==NULL) { > + printk (KERN_ERR "EEH, checking on slot with no phb dn=%s dev=%s:%s\n", > + dn->full_name, pci_name(dev), pci_pretty_name (dev)); > + return -1; > + } > + return eeh_slot_availability (dn); > +} > + > +void > +rtas_pci_slot_reset(struct device_node *dn, int state) > +{ > + int rc; > + > + if (!dn) > + return; > + if (!dn->phb) { > + printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", dn->full_name); > + return; > + } > + > + dn->eeh_mode |= EEH_MODE_RECOVERING; > + rc = rtas_call(ibm_set_slot_reset,4,1, NULL, > + dn->eeh_config_addr, > + BUID_HI(dn->phb->buid), > + BUID_LO(dn->phb->buid), > + state); > + if (rc) { > + printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d\n", rc, state); > + return; > + } > + > + if (state == 0) > + dn->eeh_mode &= ~(EEH_MODE_RECOVERING|EEH_MODE_ISOLATED); > +} > + > +/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second > + * dn -- device node to be reset. > + */ > + > +void > +rtas_set_slot_reset(struct device_node *dn) > +{ > + int i, rc; > + > + rtas_pci_slot_reset (dn, 1); > + > + /* The PCI bus requires that the reset be held high for at least > + * a 100 milliseconds. We wait a bit longer 'just in case'. */ > + > +#define PCI_BUS_RST_HOLD_TIME_MSEC 250 > + msleep (PCI_BUS_RST_HOLD_TIME_MSEC); > + rtas_pci_slot_reset (dn, 0); > + > + /* After a PCI slot has been reset, the PCI Express spec requires > + * a 1.5 second idle time for the bus to stabilize, before starting > + * up traffic. */ > +#define PCI_BUS_SETTLE_TIME_MSEC 1800 > + msleep (PCI_BUS_SETTLE_TIME_MSEC); > + > + /* Now double check with the firmware to make sure the device is > + * ready to be used; if not, wait for recovery. */ > + for (i=0; i<10; i++) { > + rc = eeh_slot_availability (dn); > + if (rc <= 0) break; > + > + msleep (rc+100); > + } > +} > + > +EXPORT_SYMBOL(rtas_set_slot_reset); > + > +void > +rtas_configure_bridge(struct device_node *dn) > +{ > + int token = rtas_token ("ibm,configure-bridge"); > + int rc; > + > + if (token == RTAS_UNKNOWN_SERVICE) > + return; > + rc = rtas_call(token,3,1, NULL, > + dn->eeh_config_addr, > + BUID_HI(dn->phb->buid), > + BUID_LO(dn->phb->buid)); > + if (rc) { > + printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", > + rc, dn->full_name); > + } > +} > + > +EXPORT_SYMBOL(rtas_configure_bridge); > + > +/* ------------------------------------------------------- */ > +/** Save and restore of PCI BARs > + * > + * Although firmware will set up BARs during boot, it doesn't > + * set up device BAR's after a device reset, although it will, > + * if requested, set up bridge configuration. Thus, we need to > + * configure the PCI devices ourselves. Config-space setup is > + * stored in the PCI structures which are normally deleted during > + * device removal. Thus, the "save" routine references the > + * structures so that they aren't deleted. > + */ > + > +/** > + * __restore_bars - Restore the Base Address Registers > + * Loads the PCI configuration space base address registers, > + * the expansion ROM base address, the latency timer, and etc. > + * from the saved values in the device node. > + */ > +static inline void __restore_bars (struct device_node *dn) > +{ > + int i; > + > + if (NULL==dn->phb) return; > + for (i=4; i<10; i++) { > + rtas_write_config(dn, i*4, 4, dn->config_space[i]); > + } > + > + /* 12 == Expansion ROM Address */ > + rtas_write_config(dn, 12*4, 4, dn->config_space[12]); > + > +#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) > +#define SAVED_BYTE(OFF) (((u8 *)(dn->config_space))[BYTE_SWAP(OFF)]) > + > + rtas_write_config (dn, PCI_CACHE_LINE_SIZE, 1, > + SAVED_BYTE(PCI_CACHE_LINE_SIZE)); > + > + rtas_write_config (dn, PCI_LATENCY_TIMER, 1, > + SAVED_BYTE(PCI_LATENCY_TIMER)); > + > + /* max latency, min grant, interrupt pin and line */ > + rtas_write_config(dn, 15*4, 4, dn->config_space[15]); > +} > + > +/** > + * eeh_restore_bars - restore the PCI config space info > + */ > +void eeh_restore_bars(struct device_node *dn) > +{ > + if (! dn->eeh_is_bridge) > + __restore_bars (dn); > + > + if (dn->child) > + eeh_restore_bars (dn->child); > +} > + > +void eeh_pci_restore_bars(struct pci_dev *dev) > +{ > + struct device_node *dn = pci_device_to_OF_node(dev); > + eeh_restore_bars (dn); > +} > + > +/* ------------------------------------------------------------- */ > +/* The code below deals with enabling EEH for devices during the > + * early boot sequence. EEH must be enabled before any PCI probing > + * can be done. > + */ > + > +#define EEH_ENABLE 1 > + > struct eeh_early_enable_info { > unsigned int buid_hi; > unsigned int buid_lo; > @@ -682,6 +885,8 @@ static void *early_enable_eeh(struct dev > int enable; > > dn->eeh_mode = 0; > + dn->eeh_check_count = 0; > + dn->eeh_freeze_count = 0; > > if (status && strcmp(status, "ok") != 0) > return NULL; /* ignore devices with bad status */ > @@ -743,7 +948,7 @@ static void *early_enable_eeh(struct dev > dn->full_name); > } > > - return NULL; > + return NULL; > } > > /* > @@ -824,11 +1029,13 @@ void eeh_add_device_early(struct device_ > struct pci_controller *phb; > struct eeh_early_enable_info info; > > - if (!dn || !eeh_subsystem_enabled) > + if (!dn) > return; > phb = dn->phb; > if (NULL == phb || 0 == phb->buid) { > - printk(KERN_WARNING "EEH: Expected buid but found none\n"); > + printk(KERN_WARNING "EEH: Expected buid but found none for %s\n", > + dn->full_name); > + dump_stack(); > return; > } > > @@ -847,6 +1054,9 @@ EXPORT_SYMBOL(eeh_add_device_early); > */ > void eeh_add_device_late(struct pci_dev *dev) > { > + int i; > + struct device_node *dn; > + > if (!dev || !eeh_subsystem_enabled) > return; > > @@ -856,6 +1066,14 @@ void eeh_add_device_late(struct pci_dev > #endif > > pci_addr_cache_insert_device (dev); > + > + /* Save the BAR's; firmware doesn't restore these after EEH reset */ > + dn = pci_device_to_OF_node(dev); > + for (i = 0; i < 16; i++) > + pci_read_config_dword(dev, i * 4, &dn->config_space[i]); > + > + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) > + dn->eeh_is_bridge = 1; > } > EXPORT_SYMBOL(eeh_add_device_late); > > @@ -885,12 +1103,17 @@ static int proc_eeh_show(struct seq_file > unsigned int cpu; > unsigned long ffs = 0, positives = 0, failures = 0; > unsigned long resets = 0; > + unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0; > > for_each_cpu(cpu) { > ffs += per_cpu(total_mmio_ffs, cpu); > positives += per_cpu(false_positives, cpu); > failures += per_cpu(ignored_failures, cpu); > resets += per_cpu(slot_resets, cpu); > + no_dev += per_cpu(no_device, cpu); > + no_dn += per_cpu(no_dn, cpu); > + no_cfg += per_cpu(no_cfg_addr, cpu); > + no_check += per_cpu(ignored_check, cpu); > } > > if (0 == eeh_subsystem_enabled) { > @@ -898,13 +1121,17 @@ static int proc_eeh_show(struct seq_file > seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs); > } else { > seq_printf(m, "EEH Subsystem is enabled\n"); > - seq_printf(m, "eeh_total_mmio_ffs=%ld\n" > + seq_printf(m, > + "no device=%ld\n" > + "no device node=%ld\n" > + "no config address=%ld\n" > + "check not wanted=%ld\n" > + "eeh_total_mmio_ffs=%ld\n" > "eeh_false_positives=%ld\n" > "eeh_ignored_failures=%ld\n" > - "eeh_slot_resets=%ld\n" > - "eeh_fail_count=%d\n", > - ffs, positives, failures, resets, > - eeh_fail_count.counter); > + "eeh_slot_resets=%ld\n", > + no_dev, no_dn, no_cfg, no_check, > + ffs, positives, failures, resets); > } > > return 0; > --- arch/ppc64/kernel/pSeries_pci.c.linas-orig 2005-04-29 20:33:03.000000000 -0500 > +++ arch/ppc64/kernel/pSeries_pci.c 2005-05-06 12:28:43.000000000 -0500 > @@ -52,7 +52,7 @@ static int s7a_workaround; > > extern struct mpic *pSeries_mpic; > > -static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) > +int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) > { > int returnval = -1; > unsigned long buid, addr; > @@ -101,7 +101,7 @@ static int rtas_pci_read_config(struct p > return PCIBIOS_DEVICE_NOT_FOUND; > } > > -static int rtas_write_config(struct device_node *dn, int where, int size, u32 val) > +int rtas_write_config(struct device_node *dn, int where, int size, u32 val) > { > unsigned long buid, addr; > int ret; > --- drivers/pci/hotplug/rpaphp.h.linas-orig 2005-04-29 20:26:21.000000000 -0500 > +++ drivers/pci/hotplug/rpaphp.h 2005-05-06 12:28:43.000000000 -0500 > @@ -118,7 +118,8 @@ extern int rpaphp_enable_pci_slot(struct > extern int register_pci_slot(struct slot *slot); > extern int rpaphp_unconfig_pci_adapter(struct slot *slot); > extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); > -extern struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev); > +extern void init_eeh_handler (void); > +extern void exit_eeh_handler (void); > > /* rpaphp_core.c */ > extern int rpaphp_add_slot(struct device_node *dn); > --- drivers/pci/hotplug/rpaphp_core.c.linas-orig 2005-04-29 20:32:16.000000000 -0500 > +++ drivers/pci/hotplug/rpaphp_core.c 2005-05-06 12:28:43.000000000 -0500 > @@ -460,12 +460,18 @@ static int __init rpaphp_init(void) > { > info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); > > + /* Get set to handle EEH events. */ > + init_eeh_handler(); > + > /* read all the PRA info from the system */ > return init_rpa(); > } > > static void __exit rpaphp_exit(void) > { > + /* Let EEH know we are going away. */ > + exit_eeh_handler(); > + > cleanup_slots(); > } > > --- drivers/pci/hotplug/rpaphp_pci.c.linas-orig 2005-04-29 20:22:38.000000000 -0500 > +++ drivers/pci/hotplug/rpaphp_pci.c 2005-05-16 11:59:30.000000000 -0500 > @@ -24,6 +24,7 @@ > */ > #include > #include > +#include > #include > #include > #include "../pci.h" /* for pci_add_new_bus */ > @@ -63,6 +64,7 @@ int rpaphp_claim_resource(struct pci_dev > root ? "Address space collision on" : > "No parent found for", > resource, dtype, pci_name(dev), res->start, res->end); > + dump_stack(); > } > return err; > } > @@ -188,6 +190,19 @@ rpaphp_fixup_new_pci_devices(struct pci_ > > static int rpaphp_pci_config_bridge(struct pci_dev *dev); > > +static void rpaphp_eeh_add_bus_device(struct pci_bus *bus) > +{ > + struct pci_dev *dev; > + list_for_each_entry(dev, &bus->devices, bus_list) { > + eeh_add_device_late(dev); > + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { > + struct pci_bus *subbus = dev->subordinate; > + if (bus) > + rpaphp_eeh_add_bus_device (subbus); > + } > + } > +} > + > /***************************************************************************** > rpaphp_pci_config_slot() will configure all devices under the > given slot->dn and return the the first pci_dev. > @@ -215,6 +230,8 @@ rpaphp_pci_config_slot(struct device_nod > } > if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) > rpaphp_pci_config_bridge(dev); > + > + rpaphp_eeh_add_bus_device(bus); > } > return dev; > } > @@ -223,7 +240,6 @@ static int rpaphp_pci_config_bridge(stru > { > u8 sec_busno; > struct pci_bus *child_bus; > - struct pci_dev *child_dev; > > dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev)); > > @@ -240,11 +256,7 @@ static int rpaphp_pci_config_bridge(stru > /* do pci_scan_child_bus */ > pci_scan_child_bus(child_bus); > > - list_for_each_entry(child_dev, &child_bus->devices, bus_list) { > - eeh_add_device_late(child_dev); > - } > - > - /* fixup new pci devices without touching bus struct */ > + /* Fixup new pci devices without touching bus struct */ > rpaphp_fixup_new_pci_devices(child_bus, 0); > > /* Make the discovered devices available */ > @@ -282,7 +294,7 @@ static void print_slot_pci_funcs(struct > return; > } > #else > -static void print_slot_pci_funcs(struct slot *slot) > +static inline void print_slot_pci_funcs(struct slot *slot) > { > return; > } > @@ -364,7 +376,6 @@ static void rpaphp_eeh_remove_bus_device > if (pdev) > rpaphp_eeh_remove_bus_device(pdev); > } > - > } > return; > } > @@ -566,36 +577,3 @@ exit: > return retval; > } > > -struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev) > -{ > - struct list_head *tmp, *n; > - struct slot *slot; > - > - list_for_each_safe(tmp, n, &rpaphp_slot_head) { > - struct pci_bus *bus; > - struct list_head *ln; > - > - slot = list_entry(tmp, struct slot, rpaphp_slot_list); > - if (slot->bridge == NULL) { > - if (slot->dev_type == PCI_DEV) { > - printk(KERN_WARNING "PCI slot missing bridge %s %s \n", > - slot->name, slot->location); > - } > - continue; > - } > - > - bus = slot->bridge->subordinate; > - if (!bus) { > - continue; /* should never happen? */ > - } > - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { > - struct pci_dev *pdev = pci_dev_b(ln); > - if (pdev == dev) > - return slot->hotplug_slot; > - } > - } > - > - return NULL; > -} > - > -EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot); > --- drivers/pci/hotplug/rpaphp_eeh.c.linas-orig 2005-05-16 11:52:15.000000000 -0500 > +++ drivers/pci/hotplug/rpaphp_eeh.c 2005-05-31 11:20:06.000000000 -0500 > @@ -0,0 +1,354 @@ > +/* > + * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform. > + * Copyright (C) 2004, 2005 Linas Vepstas > + * > + * All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or (at > + * your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or > + * NON INFRINGEMENT. See the GNU General Public License for more > + * details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + * > + * Send feedback to > + * > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "../pci.h" > +#include "rpaphp.h" > + > +/** > + * pci_search_bus_for_dev - return 1 if device is under this bus, else 0 > + * @bus: the bus to search for this device. > + * @dev: the pci device we are looking for. > + * > + * XXX should this be moved to drivers/pci/search.c ? > + */ > +static int pci_search_bus_for_dev (struct pci_bus *bus, struct pci_dev *dev) > +{ > + struct list_head *ln; > + > + if (!bus) return 0; > + > + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { > + struct pci_dev *pdev = pci_dev_b(ln); > + if (pdev == dev) > + return 1; > + if (pdev->subordinate) { > + int rc; > + rc = pci_search_bus_for_dev (pdev->subordinate, dev); > + if (rc) > + return 1; > + } > + } > + return 0; > +} > + > +/** pci_walk_bus - walk bus under this device, calling callback. > + * @top device whose peers should be walked > + * @cb callback to be called for each device found > + * @userdata arbitrary pointer to be passed to callback. > + * > + * Walk the bus on which this device sits, including any > + * bridged devices on busses under this bus. Call the provided > + * callback on each device found. > + */ > +typedef void (*pci_buswalk_cb)(struct pci_dev *, void *); > + > +static void > +pci_walk_bus (struct pci_dev *top, pci_buswalk_cb cb, void *userdata) > +{ > + struct pci_dev *dev, *tmp; > + > + spin_lock(&pci_bus_lock); > + list_for_each_entry_safe (dev, tmp, &top->bus->devices, bus_list) { > + pci_dev_get(dev); > + spin_unlock(&pci_bus_lock); > + > + /* run device routines with the bus unlocked */ > + cb (dev, userdata); > + if (dev->subordinate) { > + pci_walk_bus (pci_dev_b(&dev->subordinate->devices), cb, userdata); > + } > + spin_lock(&pci_bus_lock); > + pci_dev_put(dev); > + } > + spin_unlock(&pci_bus_lock); > +} > + > +/** > + * rpaphp_find_slot - find and return the slot holding the device > + * @dev: pci device for which we want the slot structure. > + */ > +static struct slot *rpaphp_find_slot(struct pci_dev *dev) > +{ > + struct list_head *tmp, *n; > + struct slot *slot; > + > + list_for_each_safe(tmp, n, &rpaphp_slot_head) { > + struct pci_bus *bus; > + > + slot = list_entry(tmp, struct slot, rpaphp_slot_list); > + > + /* PHB's don't have bridges. */ > + if (slot->bridge == NULL) > + continue; > + > + /* The PCI device could be the slot itself. */ > + if (slot->bridge == dev) > + return slot; > + > + bus = slot->bridge->subordinate; > + if (!bus) { > + printk (KERN_WARNING "PCI bridge is missing bus: %s %s\n", > + pci_name (slot->bridge), pci_pretty_name (slot->bridge)); > + continue; /* should never happen? */ > + } > + > + if (pci_search_bus_for_dev (bus, dev)) > + return slot; > + } > + return NULL; > +} > + > +/* ------------------------------------------------------- */ > +/** eeh_report_error - report an EEH error to each device, > + * collect up and merge the device responses. > + */ > + > +static void eeh_report_error(struct pci_dev *dev, void *userdata) > +{ > + enum pcierr_result rc, *res = userdata; > + > + if (dev->driver->err_handler.error_detected) { > + rc = dev->driver->err_handler.error_detected (dev, pci_channel_io_frozen); > + if (*res == PCIERR_RESULT_NONE) *res = rc; > + if (*res == PCIERR_RESULT_NEED_RESET) return; > + if (*res == PCIERR_RESULT_DISCONNECT && > + rc == PCIERR_RESULT_NEED_RESET) *res = rc; > + } > +} > + > +/** eeh_report_reset -- tell this device that the pci slot > + * has been reset. > + */ > + > +static void eeh_report_reset(struct pci_dev *dev, void *userdata) > +{ > + if (dev->driver->err_handler.slot_reset) > + dev->driver->err_handler.slot_reset (dev); > +} > + > +static void eeh_report_resume(struct pci_dev *dev, void *userdata) > +{ > + if (dev->driver->err_handler.resume) > + dev->driver->err_handler.resume (dev); > +} > + > +static void eeh_report_failure(struct pci_dev *dev, void *userdata) > +{ > + if (dev->driver->err_handler.error_detected) > + dev->driver->err_handler.error_detected (dev, pci_channel_io_perm_failure); > +} > + > +/* ------------------------------------------------------- */ > +/** > + * handle_eeh_events -- reset a PCI device after hard lockup. > + * > + * pSeries systems will isolate a PCI slot if the PCI-Host > + * bridge detects address or data parity errors, DMA's > + * occuring to wild addresses (which usually happen due to > + * bugs in device drivers or in PCI adapter firmware). > + * Slot isolations also occur if #SERR, #PERR or other misc > + * PCI-related errors are detected. > + * > + * Recovery process consists of unplugging the device driver > + * (which generated hotplug events to userspace), then issuing > + * a PCI #RST to the device, then reconfiguring the PCI config > + * space for all bridges & devices under this slot, and then > + * finally restarting the device drivers (which cause a second > + * set of hotplug events to go out to userspace). > + */ > + > +int eeh_reset_device (struct pci_dev *dev, struct device_node *dn, int reconfig) > +{ > + struct slot *frozen_slot= NULL; > + > + if (!dev) > + return 1; > + > + if (reconfig) > + frozen_slot = rpaphp_find_slot(dev); > + > + if (reconfig && frozen_slot) rpaphp_unconfig_pci_adapter (frozen_slot); > + > + /* Reset the pci controller. (Asserts RST#; resets config space). > + * Reconfigure bridges and devices */ > + rtas_set_slot_reset (dn->child); > + rtas_configure_bridge(dn); > + eeh_restore_bars(dn->child); > + > + enable_irq (dev->irq); > + > + /* Give the system 5 seconds to finish running the user-space > + * hotplug scripts, e.g. ifdown for ethernet. Yes, this is a hack, > + * but if we don't do this, weird things happen. > + */ > + if (reconfig && frozen_slot) { > + ssleep (5); > + rpaphp_enable_pci_slot (frozen_slot); > + } > + return 0; > +} > + > +/* The longest amount of time to wait for a pci device > + * to come back on line, in seconds. > + */ > +#define MAX_WAIT_FOR_RECOVERY 15 > + > +int handle_eeh_events (struct notifier_block *self, > + unsigned long reason, void *ev) > +{ > + int freeze_count=0; > + struct device_node *frozen_device; > + struct peh_event *event = ev; > + struct pci_dev *dev = event->dev; > + int perm_failure = 0; > + > + if (!dev) > + { > + printk ("EEH: EEH error caught, but no PCI device specified!\n"); > + return 1; > + } > + > + frozen_device = pci_bus_to_OF_node(dev->bus); > + if (!frozen_device) > + { > + printk (KERN_ERR "EEH: Cannot find PCI controller for %s %s\n", > + pci_name(dev), pci_pretty_name (dev)); > + > + return 1; > + } > + BUG_ON (frozen_device->phb==NULL); > + > + /* We get "permanent failure" messages on empty slots. > + * These are false alarms. Empty slots have no child dn. */ > + if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL)) > + return 0; > + > + if (frozen_device) > + freeze_count = frozen_device->eeh_freeze_count; > + freeze_count ++; > + if (freeze_count > EEH_MAX_ALLOWED_FREEZES) > + perm_failure = 1; > + > + /* If the reset state is a '5' and the time to reset is 0 (infinity) > + * or is more then 15 seconds, then mark this as a permanent failure. > + */ > + if ((event->state == pci_channel_io_perm_failure) && > + ((event->time_unavail <= 0) || > + (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000))) > + perm_failure = 1; > + > + /* Log the error with the rtas logger. */ > + if (perm_failure) { > + /* > + * About 90% of all real-life EEH failures in the field > + * are due to poorly seated PCI cards. Only 10% or so are > + * due to actual, failed cards. > + */ > + printk (KERN_ERR > + "EEH: device %s:%s has failed %d times \n" > + "and has been permanently disabled. Please try reseating\n" > + "this device or replacing it.\n", > + pci_name (dev), > + pci_pretty_name (dev), > + freeze_count); > + > + eeh_slot_error_detail (frozen_device, 2 /* Permanent Error */); > + > + /* Notify all devices that they're about to go down. */ > + pci_walk_bus (dev, eeh_report_failure, 0); > + > + /* If there's a hotplug slot, unconfigure it */ > + // XXX we need alternate way to deconfigure non-hotplug slots. > + struct slot * frozen_slot = rpaphp_find_slot(dev); > + if (frozen_slot) > + rpaphp_unconfig_pci_adapter (frozen_slot); > + return 1; > + } else { > + eeh_slot_error_detail (frozen_device, 1 /* Temporary Error */); > + } > + > + printk (KERN_WARNING > + "EEH: This device has failed %d times since last reboot: %s:%s\n", > + freeze_count, > + pci_name (dev), > + pci_pretty_name (dev)); > + > + /* Walk the various device drivers attached to this slot, > + * letting each know about the EEH bug. > + */ > + enum pcierr_result result = PCIERR_RESULT_NONE; > + pci_walk_bus (dev, eeh_report_error, &result); > + > + /* If all device drivers were EEH-unaware, then pci hotplug > + * the device, and hope that clears the error. */ > + if (result == PCIERR_RESULT_NONE) { > + eeh_reset_device (dev, frozen_device, 1); > + } > + > + /* If any device called out for a reset, then reset the slot */ > + if (result == PCIERR_RESULT_NEED_RESET) { > + eeh_reset_device (dev, frozen_device, 0); > + pci_walk_bus (dev, eeh_report_reset, 0); > + } > + > + /* If all devices reported they can proceed, the re-enable PIO */ > + if (result == PCIERR_RESULT_CAN_RECOVER) { > + /* XXX Not supported; we brute-force reset the device */ > + eeh_reset_device (dev, frozen_device, 0); > + pci_walk_bus (dev, eeh_report_reset, 0); > + } > + > + /* Tell all device drivers that they can resume operations */ > + pci_walk_bus (dev, eeh_report_resume, 0); > + > + /* Store the freeze count with the pci adapter, and not the slot. > + * This way, if the device is replaced, the count is cleared. > + */ > + frozen_device->eeh_freeze_count = freeze_count; > + > + return 1; > +} > + > +static struct notifier_block eeh_block; > + > +void __init init_eeh_handler (void) > +{ > + eeh_block.notifier_call = handle_eeh_events; > + peh_register_notifier (&eeh_block); > +} > + > +void __exit exit_eeh_handler (void) > +{ > + peh_unregister_notifier (&eeh_block); > +} > + > --- drivers/pci/hotplug/Makefile.linas-orig 2005-04-29 20:29:50.000000000 -0500 > +++ drivers/pci/hotplug/Makefile 2005-05-16 11:53:52.000000000 -0500 > @@ -41,6 +41,7 @@ acpiphp-objs := acpiphp_core.o \ > acpiphp_res.o > > rpaphp-objs := rpaphp_core.o \ > + rpaphp_eeh.o \ > rpaphp_pci.o \ > rpaphp_slot.o \ > rpaphp_vio.o > > > ------------------------------------------------------------------------ > > _______________________________________________ > Linuxppc64-dev mailing list > Linuxppc64-dev at ozlabs.org > https://ozlabs.org/cgi-bin/mailman/listinfo/linuxppc64-dev -- Brian King eServer Storage I/O IBM Linux Technology Center From johnrose at austin.ibm.com Thu Jun 2 04:10:36 2005 From: johnrose at austin.ibm.com (John Rose) Date: Wed, 01 Jun 2005 13:10:36 -0500 Subject: [PATCH] initialize TCE tables Message-ID: <1117649436.28482.3.camel@sinatra.austin.ibm.com> A fairly recent platform requirement states that the OS must clear the whole TCE table at setup time, in case firmware left any active mappings in it. Without this initialization, dynamic bus removes can fail. Firmware rejects these requests if active mappings still exist for a slot that has been deallocated by the OS. If there are no objections, I'll forward this to Andrew Morton. Thanks- John Signed-off-by: Olof Johansson Signed-off-by: John Rose diff -puN arch/ppc64/kernel/iommu.c~initialize_tces arch/ppc64/kernel/iommu.c --- 2_6_linus_2/arch/ppc64/kernel/iommu.c~initialize_tces 2005-06-01 12:17:53.000000000 -0500 +++ 2_6_linus_2-johnrose/arch/ppc64/kernel/iommu.c 2005-06-01 12:19:56.000000000 -0500 @@ -423,6 +423,9 @@ struct iommu_table *iommu_init_table(str tbl->it_largehint = tbl->it_halfpoint; spin_lock_init(&tbl->it_lock); + /* Clear the hardware table in case firmware left allocations in it */ + ppc_md.tce_free(tbl, 0, tbl->it_size); + if (!welcomed) { printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", novmerge ? "disabled" : "enabled"); _ From benh at kernel.crashing.org Thu Jun 2 08:22:02 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 08:22:02 +1000 Subject: [PATCH] ppc64: fix call_prom return checks Message-ID: <1117664522.19020.75.camel@gaston> Hi Arnd, Paul ! What about this patch ? (untested at the moment). I'm never very comfortable with those sign non-extension issues in prom_init ... It also fixes another 32 vs. 64 bytes issue on properties. Ben. Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-02 08:11:37.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-02 08:19:27.000000000 +1000 @@ -1062,7 +1062,7 @@ prom_printf("opening PHB %s", path); phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) + if (phb_node == ~0u) prom_printf("... failed\n"); else prom_printf("... done\n"); @@ -1279,12 +1279,12 @@ /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) + if ((long)_prom->chosen == ~0u) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) + if ((long)_prom->root == ~0u) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ } @@ -1426,7 +1426,7 @@ * leave some room at the end of the path for appending extra * arguments */ - if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) == ~0u) continue; prom_printf("found display : %s, opening ... ", path); @@ -1514,6 +1514,12 @@ return 0; } +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1528,9 +1534,9 @@ prev_name = RELOC(""); for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, 32, 1); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* 64 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) == ~0u) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; @@ -1555,12 +1561,6 @@ } } -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1607,7 +1607,7 @@ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + if (call_prom("nextprop", 3, 1, node, prev_name, pname) == ~0u) break; /* find string offset */ @@ -1623,7 +1623,7 @@ l = call_prom("getproplen", 2, 1, node, pname); /* sanity checks */ - if (l < 0) + if (l == ~0u) continue; if (l > MAX_PROPERTY_LENGTH) { prom_printf("WARNING: ignoring large property "); @@ -1771,13 +1771,13 @@ /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000")); - if ((long)u3 <= 0) + if (u3 == ~0u) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/i2c at f8001000")); - if ((long)i2c <= 0) + if (i2c <= ~0u) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/mpic at f8040000")); - if ((long)mpic <= 0) + if (mpic <= ~0u) return; /* check if proper rev of u3 */ From benh at kernel.crashing.org Thu Jun 2 08:25:00 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 08:25:00 +1000 Subject: [PATCH] ppc64: set/clear SMT capable bit at boot In-Reply-To: <429BF93F.1030301@austin.ibm.com> References: <20050529234154.GG11066@krispykreme> <429BF93F.1030301@austin.ibm.com> Message-ID: <1117664701.19020.79.camel@gaston> On Tue, 2005-05-31 at 00:42 -0500, Joel Schopp wrote: > > + if (prop && ((size / sizeof(u32)) > 1)) > > If this hasn't gone out yet it might be nice to add a BUG_ON((size / > sizeof(u32)) > 2). I don't know of any processors that do more than 2 > way SMT, but if one comes out several years from now it would be nice to > catch it early. Mostly I'd like the extra BUG_ON() in order to have one > more check against buggy firmware. > > Patch looks fine with our without the extra BUG_ON() Rather than BUG_ON, just keep SMT feature cleared and dump something in dmesg, let's me kind to users, we are very early during boot, it would be a bit difficult to track down that BUG (no console yet). Ben. From arnd at arndb.de Thu Jun 2 08:20:16 2005 From: arnd at arndb.de (Arnd Bergmann) Date: Thu, 2 Jun 2005 00:20:16 +0200 Subject: [PATCH] ppc64: fix call_prom return checks In-Reply-To: <1117664522.19020.75.camel@gaston> References: <1117664522.19020.75.camel@gaston> Message-ID: <200506020020.16663.arnd@arndb.de> On Dunnersdag 02 Juni 2005 00:22, Benjamin Herrenschmidt wrote: > Hi Arnd, Paul ! > > What about this patch ? (untested at the moment). I'm never very > comfortable with those sign non-extension issues in prom_init ... Why do you cast the values to 'long' in the first place? Comparing two values of the same type would seem more intuitive. Aside from that, the patch looks good to me, I'll give it a test run on our firmware tomorrow. Arnd <>< From benh at kernel.crashing.org Thu Jun 2 08:48:06 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 08:48:06 +1000 Subject: [PATCH] ppc64: fix call_prom return checks In-Reply-To: <200506020020.16663.arnd@arndb.de> References: <1117664522.19020.75.camel@gaston> <200506020020.16663.arnd@arndb.de> Message-ID: <1117666087.19020.96.camel@gaston> On Thu, 2005-06-02 at 00:20 +0200, Arnd Bergmann wrote: > On Dunnersdag 02 Juni 2005 00:22, Benjamin Herrenschmidt wrote: > > Hi Arnd, Paul ! > > > > What about this patch ? (untested at the moment). I'm never very > > comfortable with those sign non-extension issues in prom_init ... > > Why do you cast the values to 'long' in the first place My patch is still doing that ? I though I was removing those casts ... > Comparing two values of the same type would seem more intuitive. > Aside from that, the patch looks good to me, I'll give it a test > run on our firmware tomorrow. From arnd at arndb.de Thu Jun 2 08:54:23 2005 From: arnd at arndb.de (Arnd Bergmann) Date: Thu, 2 Jun 2005 00:54:23 +0200 Subject: [PATCH] ppc64: fix call_prom return checks In-Reply-To: <1117666087.19020.96.camel@gaston> References: <1117664522.19020.75.camel@gaston> <200506020020.16663.arnd@arndb.de> <1117666087.19020.96.camel@gaston> Message-ID: <200506020054.24224.arnd@arndb.de> On Dunnersdag 02 Juni 2005 00:48, Benjamin Herrenschmidt wrote: > My patch is still doing that ? I though I was removing those casts ... You removed most of them, but two are still left. Arnd <>< From benh at kernel.crashing.org Thu Jun 2 11:24:22 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 11:24:22 +1000 Subject: [PATCH] ppc64: fix call_prom return checks In-Reply-To: <200506020054.24224.arnd@arndb.de> References: <1117664522.19020.75.camel@gaston> <200506020020.16663.arnd@arndb.de> <1117666087.19020.96.camel@gaston> <200506020054.24224.arnd@arndb.de> Message-ID: <1117675462.19020.106.camel@gaston> On Thu, 2005-06-02 at 00:54 +0200, Arnd Bergmann wrote: > On Dunnersdag 02 Juni 2005 00:48, Benjamin Herrenschmidt wrote: > > My patch is still doing that ? I though I was removing those casts ... > > You removed most of them, but two are still left. Ok, let's be clean. If I define PROM_ERROR to be (-1u) instead of (-1), it actually works in all cases without needing ugly casts. What about this patch ? Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-02 08:11:37.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-02 11:24:05.000000000 +1000 @@ -216,7 +216,7 @@ * mode when we do. We switch back to 64b mode upon return. */ -#define PROM_ERROR (-1) +#define PROM_ERROR (-1u) static int __init call_prom(const char *service, int nargs, int nret, ...) { @@ -587,14 +587,13 @@ { unsigned long offset = reloc_offset(); ihandle elfloader; - int ret; elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); - if (elfloader == 0) { + if (elfloader == PROM_ERROR || elfloader == 0) { prom_printf("couldn't open /packages/elf-loader\n"); return; } - ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), + call_prom("call-method", 3, 1, ADDR("process-elf-header"), elfloader, ADDR(&fake_elf)); call_prom("close", 1, 0, elfloader); } @@ -646,7 +645,7 @@ base = _ALIGN_UP(base + 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; if (align == 0) @@ -708,7 +707,7 @@ for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; } @@ -910,7 +909,7 @@ prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); prom_debug("prom_rtas: %x\n", prom_rtas); - if (prom_rtas == (phandle) -1) + if (prom_rtas == PROM_ERROR) return; prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); @@ -1062,7 +1061,7 @@ prom_printf("opening PHB %s", path); phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) + if (phb_node == PROM_ERROR) prom_printf("... failed\n"); else prom_printf("... done\n"); @@ -1279,12 +1278,12 @@ /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) + if (_prom->chosen == PROM_ERROR) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) + if (_prom->root == PROM_ERROR) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ } @@ -1356,9 +1355,8 @@ } /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (rtas != (phandle) -1) { - unsigned long x; - x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (rtas != PROM_ERROR) { + int x = prom_getproplen(rtas, "ibm,hypertas-functions"); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); return PLATFORM_PSERIES_LPAR; @@ -1426,12 +1424,13 @@ * leave some room at the end of the path for appending extra * arguments */ - if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + if (call_prom("package-to-path", 3, 1, node, path, + PROM_SCRATCH_SIZE-10) == PRROM_ERROR) continue; prom_printf("found display : %s, opening ... ", path); ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { + if (ih == 0 || ih == PROM_ERROR) { prom_printf("failed\n"); continue; } @@ -1514,6 +1513,12 @@ return 0; } +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1528,9 +1533,10 @@ prev_name = RELOC(""); for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, 32, 1); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* 64 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) + == PROM_ERROR) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; @@ -1555,12 +1561,6 @@ } } -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1607,7 +1607,8 @@ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + if (call_prom("nextprop", 3, 1, node, prev_name, pname) + == PROM_ERROR) break; /* find string offset */ @@ -1623,7 +1624,7 @@ l = call_prom("getproplen", 2, 1, node, pname); /* sanity checks */ - if (l < 0) + if (l == PROM_ERROR) continue; if (l > MAX_PROPERTY_LENGTH) { prom_printf("WARNING: ignoring large property "); @@ -1771,17 +1772,18 @@ /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000")); - if ((long)u3 <= 0) + if (u3 == PROM_ERROR) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/i2c at f8001000")); - if ((long)i2c <= 0) + if (i2c <= PROM_ERROR) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/mpic at f8040000")); - if ((long)mpic <= 0) + if (mpic <= PROM_ERROR) return; /* check if proper rev of u3 */ - if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) + == PROM_ERROR) return; if (u3_rev != 0x35) return; From benh at kernel.crashing.org Thu Jun 2 11:35:05 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 11:35:05 +1000 Subject: [PATCH] ppc64: fix call_prom return checks In-Reply-To: <1117675462.19020.106.camel@gaston> References: <1117664522.19020.75.camel@gaston> <200506020020.16663.arnd@arndb.de> <1117666087.19020.96.camel@gaston> <200506020054.24224.arnd@arndb.de> <1117675462.19020.106.camel@gaston> Message-ID: <1117676106.19020.111.camel@gaston> On Thu, 2005-06-02 at 11:24 +1000, Benjamin Herrenschmidt wrote: > On Thu, 2005-06-02 at 00:54 +0200, Arnd Bergmann wrote: > > On Dunnersdag 02 Juni 2005 00:48, Benjamin Herrenschmidt wrote: > > > My patch is still doing that ? I though I was removing those casts ... > > > > You removed most of them, but two are still left. > > Ok, let's be clean. If I define PROM_ERROR to be (-1u) instead of (-1), > it actually works in all cases without needing ugly casts. What about > this patch ? Or better, the one that actually builds :) Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-02 08:11:37.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-02 11:33:21.000000000 +1000 @@ -216,7 +216,7 @@ * mode when we do. We switch back to 64b mode upon return. */ -#define PROM_ERROR (-1) +#define PROM_ERROR (-1u) static int __init call_prom(const char *service, int nargs, int nret, ...) { @@ -587,14 +587,13 @@ { unsigned long offset = reloc_offset(); ihandle elfloader; - int ret; elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); - if (elfloader == 0) { + if (elfloader == PROM_ERROR || elfloader == 0) { prom_printf("couldn't open /packages/elf-loader\n"); return; } - ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), + call_prom("call-method", 3, 1, ADDR("process-elf-header"), elfloader, ADDR(&fake_elf)); call_prom("close", 1, 0, elfloader); } @@ -646,7 +645,7 @@ base = _ALIGN_UP(base + 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; if (align == 0) @@ -708,7 +707,7 @@ for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; } @@ -910,7 +909,7 @@ prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); prom_debug("prom_rtas: %x\n", prom_rtas); - if (prom_rtas == (phandle) -1) + if (prom_rtas == PROM_ERROR) return; prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); @@ -1062,7 +1061,7 @@ prom_printf("opening PHB %s", path); phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) + if (phb_node == PROM_ERROR) prom_printf("... failed\n"); else prom_printf("... done\n"); @@ -1279,12 +1278,12 @@ /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) + if (_prom->chosen == PROM_ERROR) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) + if (_prom->root == PROM_ERROR) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ } @@ -1356,9 +1355,8 @@ } /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (rtas != (phandle) -1) { - unsigned long x; - x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (rtas != PROM_ERROR) { + int x = prom_getproplen(rtas, "ibm,hypertas-functions"); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); return PLATFORM_PSERIES_LPAR; @@ -1426,12 +1424,13 @@ * leave some room at the end of the path for appending extra * arguments */ - if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + if (call_prom("package-to-path", 3, 1, node, path, + PROM_SCRATCH_SIZE-10) == PROM_ERROR) continue; prom_printf("found display : %s, opening ... ", path); ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { + if (ih == 0 || ih == PROM_ERROR) { prom_printf("failed\n"); continue; } @@ -1514,6 +1513,12 @@ return 0; } +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1528,9 +1533,10 @@ prev_name = RELOC(""); for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, 32, 1); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* 64 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) + == PROM_ERROR) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; @@ -1555,12 +1561,6 @@ } } -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1607,7 +1607,8 @@ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + if (call_prom("nextprop", 3, 1, node, prev_name, pname) + == PROM_ERROR) break; /* find string offset */ @@ -1623,7 +1624,7 @@ l = call_prom("getproplen", 2, 1, node, pname); /* sanity checks */ - if (l < 0) + if (l == PROM_ERROR) continue; if (l > MAX_PROPERTY_LENGTH) { prom_printf("WARNING: ignoring large property "); @@ -1771,17 +1772,18 @@ /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000")); - if ((long)u3 <= 0) + if (u3 == PROM_ERROR) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/i2c at f8001000")); - if ((long)i2c <= 0) + if (i2c <= PROM_ERROR) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/mpic at f8040000")); - if ((long)mpic <= 0) + if (mpic <= PROM_ERROR) return; /* check if proper rev of u3 */ - if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) + == PROM_ERROR) return; if (u3_rev != 0x35) return; From benh at kernel.crashing.org Thu Jun 2 14:11:37 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Thu, 02 Jun 2005 14:11:37 +1000 Subject: [PATCH] ppc64: Fix result code handling in prom_init Message-ID: <1117685497.31082.27.camel@gaston> Hi ! prom_init(), the trampoline code that "talks" to Open Firmware during early boot, has various issues with managing OF result codes. Some of my recent fixups in fact made the problem worse on some platforms. This patch reworks it all. Tested on g5, Maple, POWER3 and POWER5. Signed-off-by: Benjamin Herrenschmidt Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-02 08:11:37.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-02 14:03:54.000000000 +1000 @@ -211,13 +211,23 @@ */ #define ADDR(x) (u32) ((unsigned long)(x) - offset) +/* + * Error results ... some OF calls will return "-1" on error, some + * will return 0, some will return either. To simplify, here are + * macros to use with any ihandle or phandle return value to check if + * it is valid + */ + +#define PROM_ERROR (-1u) +#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR) +#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR) + + /* This is the one and *ONLY* place where we actually call open * firmware from, since we need to make sure we're running in 32b * mode when we do. We switch back to 64b mode upon return. */ -#define PROM_ERROR (-1) - static int __init call_prom(const char *service, int nargs, int nret, ...) { int i; @@ -587,14 +597,13 @@ { unsigned long offset = reloc_offset(); ihandle elfloader; - int ret; elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); if (elfloader == 0) { prom_printf("couldn't open /packages/elf-loader\n"); return; } - ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), + call_prom("call-method", 3, 1, ADDR("process-elf-header"), elfloader, ADDR(&fake_elf)); call_prom("close", 1, 0, elfloader); } @@ -646,7 +655,7 @@ base = _ALIGN_UP(base + 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; if (align == 0) @@ -708,7 +717,7 @@ for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if ((int)addr != PROM_ERROR) + if (addr != PROM_ERROR) break; addr = 0; } @@ -902,18 +911,19 @@ { unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); - phandle prom_rtas, rtas_node; + phandle rtas_node; + ihandle rtas_inst; u32 base, entry = 0; u32 size = 0; prom_debug("prom_instantiate_rtas: start...\n"); - prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - prom_debug("prom_rtas: %x\n", prom_rtas); - if (prom_rtas == (phandle) -1) + rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas")); + prom_debug("rtas_node: %x\n", rtas_node); + if (!PHANDLE_VALID(rtas_node)) return; - prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); + prom_getprop(rtas_node, "rtas-size", &size, sizeof(size)); if (size == 0) return; @@ -922,14 +932,18 @@ prom_printf("RTAS allocation failed !\n"); return; } - prom_printf("instantiating rtas at 0x%x", base); - rtas_node = call_prom("open", 1, 1, ADDR("/rtas")); - prom_printf("..."); + rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); + if (!IHANDLE_VALID(rtas_inst)) { + prom_printf("opening rtas package failed"); + return; + } + + prom_printf("instantiating rtas at 0x%x ...", base); if (call_prom("call-method", 3, 2, ADDR("instantiate-rtas"), - rtas_node, base) != PROM_ERROR) { + rtas_inst, base) != PROM_ERROR) { entry = (long)_prom->args.rets[1]; } if (entry == 0) { @@ -940,8 +954,8 @@ reserve_mem(base, size); - prom_setprop(prom_rtas, "linux,rtas-base", &base, sizeof(base)); - prom_setprop(prom_rtas, "linux,rtas-entry", &entry, sizeof(entry)); + prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); + prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas entry = 0x%x\n", entry); @@ -1062,7 +1076,7 @@ prom_printf("opening PHB %s", path); phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) + if (phb_node == 0) prom_printf("... failed\n"); else prom_printf("... done\n"); @@ -1279,12 +1293,12 @@ /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) + if (!PHANDLE_VALID(_prom->chosen)) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) + if (!PHANDLE_VALID(_prom->root)) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ } @@ -1356,9 +1370,8 @@ } /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (rtas != (phandle) -1) { - unsigned long x; - x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (!PHANDLE_VALID(rtas)) { + int x = prom_getproplen(rtas, "ibm,hypertas-functions"); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); return PLATFORM_PSERIES_LPAR; @@ -1426,12 +1439,13 @@ * leave some room at the end of the path for appending extra * arguments */ - if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + if (call_prom("package-to-path", 3, 1, node, path, + PROM_SCRATCH_SIZE-10) == PROM_ERROR) continue; prom_printf("found display : %s, opening ... ", path); ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { + if (ih == 0) { prom_printf("failed\n"); continue; } @@ -1514,6 +1528,12 @@ return 0; } +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1527,10 +1547,12 @@ /* get and store all property names */ prev_name = RELOC(""); for (;;) { - - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, 32, 1); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + int rc; + + /* 64 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); + rc = call_prom("nextprop", 3, 1, node, prev_name, namep); + if (rc != 1) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; @@ -1555,12 +1577,6 @@ } } -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1607,7 +1623,10 @@ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + int rc; + + rc = call_prom("nextprop", 3, 1, node, prev_name, pname); + if (rc != 1) break; /* find string offset */ @@ -1623,7 +1642,7 @@ l = call_prom("getproplen", 2, 1, node, pname); /* sanity checks */ - if (l < 0) + if (l == PROM_ERROR) continue; if (l > MAX_PROPERTY_LENGTH) { prom_printf("WARNING: ignoring large property "); @@ -1771,17 +1790,18 @@ /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000")); - if ((long)u3 <= 0) + if (!PHANDLE_VALID(u3)) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/i2c at f8001000")); - if ((long)i2c <= 0) + if (!PHANDLE_VALID(i2c)) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3 at 0,f8000000/mpic at f8040000")); - if ((long)mpic <= 0) + if (!PHANDLE_VALID(mpic)) return; /* check if proper rev of u3 */ - if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) + == PROM_ERROR) return; if (u3_rev != 0x35) return; From sfr at canb.auug.org.au Thu Jun 2 16:41:49 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 16:41:49 +1000 Subject: [PATCH] iSeries: remove include/asm-ppc64/iSeries/LparData.h Message-ID: <20050602164149.1cb5902e.sfr@canb.auug.org.au> Hi all, include/asm-ppc64/iSeries/LparData.h just included a whole loat of other files to declare variables that would be better declared in those other files. So, remove it. This should reduce that number of things needed to be included in most cases to access the relevant variables. arch/ppc64/kernel/HvLpEvent.c | 2 - arch/ppc64/kernel/ItLpQueue.c | 1 arch/ppc64/kernel/iSeries_VpdInfo.c | 1 arch/ppc64/kernel/iSeries_pci.c | 1 arch/ppc64/kernel/iSeries_proc.c | 2 - arch/ppc64/kernel/iSeries_setup.c | 5 ++ arch/ppc64/kernel/iSeries_smp.c | 1 arch/ppc64/kernel/irq.c | 2 - arch/ppc64/kernel/lparcfg.c | 2 - arch/ppc64/kernel/ras.c | 1 arch/ppc64/kernel/rtc.c | 1 arch/ppc64/kernel/setup.c | 3 + arch/ppc64/kernel/viopath.c | 2 - include/asm-ppc64/iSeries/HvLpConfig.h | 1 include/asm-ppc64/iSeries/HvReleaseData.h | 2 + include/asm-ppc64/iSeries/IoHriMainStore.h | 2 + include/asm-ppc64/iSeries/IoHriProcessorVpd.h | 2 + include/asm-ppc64/iSeries/ItExtVpdPanel.h | 2 + include/asm-ppc64/iSeries/ItIplParmsReal.h | 2 + include/asm-ppc64/iSeries/ItLpNaca.h | 4 ++ include/asm-ppc64/iSeries/ItVpdAreas.h | 2 + include/asm-ppc64/iSeries/LparData.h | 48 -------------------------- include/asm-ppc64/iSeries/LparMap.h | 2 + 23 files changed, 29 insertions(+), 62 deletions(-) This is on top of my previous iSeries header cleanup. -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/HvLpEvent.c linus-iSeries-headers.2/arch/ppc64/kernel/HvLpEvent.c --- linus-iSeries-headers.1/arch/ppc64/kernel/HvLpEvent.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/HvLpEvent.c 2005-06-02 15:17:50.000000000 +1000 @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* Array of LpEvent handler functions */ LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/ItLpQueue.c linus-iSeries-headers.2/arch/ppc64/kernel/ItLpQueue.c --- linus-iSeries-headers.1/arch/ppc64/kernel/ItLpQueue.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/ItLpQueue.c 2005-06-02 16:07:50.000000000 +1000 @@ -16,7 +16,6 @@ #include #include #include -#include static __inline__ int set_inUse( struct ItLpQueue * lpQueue ) { diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_VpdInfo.c linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_VpdInfo.c --- linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_VpdInfo.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_VpdInfo.c 2005-06-02 16:08:05.000000000 +1000 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "pci.h" diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_pci.c linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_pci.c --- linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_pci.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_pci.c 2005-06-02 16:16:36.000000000 +1000 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_proc.c linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_proc.c --- linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_proc.c 2005-06-01 17:53:28.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_proc.c 2005-06-02 16:08:14.000000000 +1000 @@ -28,7 +28,7 @@ #include #include #include -#include +#include static int __init iseries_proc_create(void) { diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_setup.c linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_setup.c --- linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_setup.c 2005-06-01 18:18:38.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_setup.c 2005-06-02 16:28:19.000000000 +1000 @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,6 +58,9 @@ #include #include #include +#include +#include +#include extern void hvlog(char *fmt, ...); diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_smp.c linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_smp.c --- linus-iSeries-headers.1/arch/ppc64/kernel/iSeries_smp.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_smp.c 2005-06-02 16:18:02.000000000 +1000 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/irq.c linus-iSeries-headers.2/arch/ppc64/kernel/irq.c --- linus-iSeries-headers.1/arch/ppc64/kernel/irq.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/irq.c 2005-06-02 15:48:09.000000000 +1000 @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/lparcfg.c linus-iSeries-headers.2/arch/ppc64/kernel/lparcfg.c --- linus-iSeries-headers.1/arch/ppc64/kernel/lparcfg.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/lparcfg.c 2005-06-02 16:08:22.000000000 +1000 @@ -28,12 +28,12 @@ #include #include #include -#include #include #include #include #include #include +#include #define MODULE_VERS "1.6" #define MODULE_NAME "lparcfg" diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/ras.c linus-iSeries-headers.2/arch/ppc64/kernel/ras.c --- linus-iSeries-headers.1/arch/ppc64/kernel/ras.c 2005-05-20 09:03:14.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/ras.c 2005-06-02 16:07:59.000000000 +1000 @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/rtc.c linus-iSeries-headers.2/arch/ppc64/kernel/rtc.c --- linus-iSeries-headers.1/arch/ppc64/kernel/rtc.c 2005-05-26 10:44:08.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/rtc.c 2005-06-02 16:18:54.000000000 +1000 @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/setup.c linus-iSeries-headers.2/arch/ppc64/kernel/setup.c --- linus-iSeries-headers.1/arch/ppc64/kernel/setup.c 2005-05-20 09:03:14.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/setup.c 2005-06-02 16:07:41.000000000 +1000 @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,8 @@ #include #include #include +#include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff -ruNp linus-iSeries-headers.1/arch/ppc64/kernel/viopath.c linus-iSeries-headers.2/arch/ppc64/kernel/viopath.c --- linus-iSeries-headers.1/arch/ppc64/kernel/viopath.c 2005-06-01 17:54:00.000000000 +1000 +++ linus-iSeries-headers.2/arch/ppc64/kernel/viopath.c 2005-06-02 16:19:39.000000000 +1000 @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvLpConfig.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvLpConfig.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-01 16:08:25.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-02 16:21:09.000000000 +1000 @@ -27,7 +27,6 @@ #include #include #include -#include extern HvLpIndex HvLpConfig_getLpIndex_outline(void); diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvReleaseData.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvReleaseData.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvReleaseData.h 2005-06-01 16:39:29.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvReleaseData.h 2005-06-02 15:07:40.000000000 +1000 @@ -58,4 +58,6 @@ struct HvReleaseData { char xRsvd3[20]; /* Reserved x2C-x3F */ }; +extern struct HvReleaseData hvReleaseData; + #endif /* _HVRELEASEDATA_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/IoHriMainStore.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/IoHriMainStore.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/IoHriMainStore.h 2005-06-01 16:47:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/IoHriMainStore.h 2005-06-02 16:06:25.000000000 +1000 @@ -161,4 +161,6 @@ struct IoHriMainStoreSegment5 { u64 reserved3; }; +extern u64 xMsVpd[]; + #endif /* _IOHRIMAINSTORE_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/IoHriProcessorVpd.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/IoHriProcessorVpd.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/IoHriProcessorVpd.h 2005-06-01 16:50:11.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/IoHriProcessorVpd.h 2005-06-02 15:27:50.000000000 +1000 @@ -81,4 +81,6 @@ struct IoHriProcessorVpd { char xProcSrc[72]; // CSP format SRC xB8-xFF }; +extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; + #endif /* _IOHRIPROCESSORVPD_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItExtVpdPanel.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItExtVpdPanel.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItExtVpdPanel.h 2005-06-01 16:51:48.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItExtVpdPanel.h 2005-06-02 15:22:18.000000000 +1000 @@ -47,4 +47,6 @@ struct ItExtVpdPanel { u8 xRsvd2[48]; }; +extern struct ItExtVpdPanel xItExtVpdPanel; + #endif /* _ITEXTVPDPANEL_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItIplParmsReal.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItIplParmsReal.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItIplParmsReal.h 2005-06-01 16:53:52.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItIplParmsReal.h 2005-06-02 15:05:43.000000000 +1000 @@ -66,4 +66,6 @@ struct ItIplParmsReal { u64 xRsvd13; // Reserved x38-x3F }; +extern struct ItIplParmsReal xItIplParmsReal; + #endif /* _ITIPLPARMSREAL_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItLpNaca.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItLpNaca.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItLpNaca.h 2005-06-01 16:58:28.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItLpNaca.h 2005-06-02 15:10:27.000000000 +1000 @@ -19,6 +19,8 @@ #ifndef _ITLPNACA_H #define _ITLPNACA_H +#include + /* * This control block contains the data that is shared between the * hypervisor (PLIC) and the OS. @@ -73,4 +75,6 @@ struct ItLpNaca { u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF }; +extern struct ItLpNaca itLpNaca; + #endif /* _ITLPNACA_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItVpdAreas.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItVpdAreas.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/ItVpdAreas.h 2005-06-01 17:11:03.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/ItVpdAreas.h 2005-06-02 16:22:09.000000000 +1000 @@ -90,4 +90,6 @@ struct ItVpdAreas { void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF }; +extern struct ItVpdAreas itVpdAreas; + #endif /* _ITVPDAREAS_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/LparData.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/LparData.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/LparData.h 2005-06-01 17:12:42.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/LparData.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,48 +0,0 @@ -/* - * LparData.h - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LPARDATA_H -#define _LPARDATA_H - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct LparMap xLparMap; -extern struct HvReleaseData hvReleaseData; -extern struct ItLpNaca itLpNaca; -extern struct ItIplParmsReal xItIplParmsReal; -extern struct ItExtVpdPanel xItExtVpdPanel; -extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; -extern struct ItLpQueue xItLpQueue; -extern struct ItVpdAreas itVpdAreas; -extern u64 xMsVpd[]; -extern struct msChunks msChunks; - -#endif /* _LPARDATA_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/LparMap.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/LparMap.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/LparMap.h 2005-06-01 17:14:45.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/LparMap.h 2005-06-02 15:21:09.000000000 +1000 @@ -64,4 +64,6 @@ struct LparMap { u64 xVPN; // Virtual Page Number (0x000C000000000000) }; +extern struct LparMap xLparMap; + #endif /* _LPARMAP_H */ -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/20184c0f/attachment.pgp From david at gibson.dropbear.id.au Thu Jun 2 17:09:18 2005 From: david at gibson.dropbear.id.au (David Gibson) Date: Thu, 2 Jun 2005 17:09:18 +1000 Subject: Booting the linux-ppc64 kernel & flattened device tree v0.4 In-Reply-To: <1117614390.19020.24.camel@gaston> References: <1117614390.19020.24.camel@gaston> Message-ID: <20050602070918.GI4748@localhost.localdomain> On Wed, Jun 01, 2005 at 06:26:30PM +1000, Benjamin Herrenschmidt wrote: > DO NOT REPLY TO ALL LISTS PLEASE ! (and CC me on replies). > > Here's the fourth version of my document along with new kernel patches > for the new improved flattened format, and the first release of the > device-tree "compiler" tool. The patches will be posted as a reply to > this email. The compiler, dtc, can be downloaded, the URL is in the > document. [snip] > IV - "dtc", the device tree compiler > ==================================== > > dtc source code can be found at > I've just updated the dtc tarball with a new version. Notable changes: - Corrected comment parsing - Corrected handling of #address-cells, #size-cells properties - Input from device tree blobs should actually work now - Corrected autogeneration of "name" properties in blob/asm output version < 0x10 - Added a TODO list -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/people/dgibson From sfr at canb.auug.org.au Thu Jun 2 17:19:54 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 17:19:54 +1000 Subject: [PATCH] iSeries: eliminate some unused inlines Message-ID: <20050602171954.010339aa.sfr@canb.auug.org.au> Hi all, This patch removes a large number of inline functions that are not used. It also changes the only caller of a HvCallCfg function that is outside HvLpConfig.h to its equivalent HvLpConfig function and no longer includes HvCallCfg.h where it is not needed. arch/ppc64/kernel/iSeries_smp.c | 1 arch/ppc64/kernel/viopath.c | 3 include/asm-ppc64/iSeries/HvCallCfg.h | 53 --------- include/asm-ppc64/iSeries/HvLpConfig.h | 188 --------------------------------- 4 files changed, 3 insertions(+), 242 deletions(-) Relative to my previous to iSeries header cleanups. -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_smp.c linus-iSeries-headers.3/arch/ppc64/kernel/iSeries_smp.c --- linus-iSeries-headers.2/arch/ppc64/kernel/iSeries_smp.c 2005-06-02 16:18:02.000000000 +1000 +++ linus-iSeries-headers.3/arch/ppc64/kernel/iSeries_smp.c 2005-06-02 17:11:29.000000000 +1000 @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.2/arch/ppc64/kernel/viopath.c linus-iSeries-headers.3/arch/ppc64/kernel/viopath.c --- linus-iSeries-headers.2/arch/ppc64/kernel/viopath.c 2005-06-02 16:19:39.000000000 +1000 +++ linus-iSeries-headers.3/arch/ppc64/kernel/viopath.c 2005-06-02 17:06:58.000000000 +1000 @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -364,7 +363,7 @@ void vio_set_hostlp(void) * while we're active */ viopath_ourLp = HvLpConfig_getLpIndex(); - viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp); + viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); if (viopath_hostLp != HvLpIndexInvalid) vio_setHandler(viomajorsubtype_config, handleConfig); diff -ruNp linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallCfg.h linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvCallCfg.h --- linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallCfg.h 2005-06-01 15:04:06.000000000 +1000 +++ linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvCallCfg.h 2005-06-02 17:08:25.000000000 +1000 @@ -67,31 +67,11 @@ enum HvCallCfg_ReqQual { #define HvCallCfgGetLpExecutionMode HvCallCfg + 31 #define HvCallCfgGetHostingLpIndex HvCallCfg + 32 -static inline HvLpIndex HvCallCfg_getLps(void) -{ - return HvCall0(HvCallCfgGetLps); -} - -static inline int HvCallCfg_isBusDedicated(u64 busIndex) -{ - return HvCall1(HvCallCfgIsBusDedicated, busIndex); -} - static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) { return HvCall1(HvCallCfgGetBusOwner, busIndex); } -static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) -{ - return HvCall1(HvCallCfgGetBusAllocation, busIndex); -} - -static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) -{ - return HvCall0(HvCallCfgGetActiveLpMap); -} - static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( HvLpIndex lp) { @@ -105,31 +85,12 @@ static inline HvLpVirtualLanIndexMap HvC return retVal; } -static inline u64 HvCallCfg_getSystemMsChunks(void) -{ - return HvCall0(HvCallCfgGetSystemMsChunks); -} - static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, enum HvCallCfg_ReqQual qual) { return HvCall2(HvCallCfgGetMsChunks, lp, qual); } -static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) -{ - /* - * NOTE: This function was added in v5r1 so older hypervisors - * will return a -1 value - */ - return HvCall1(HvCallCfgGetMinRuntimeMsChunks, lp); -} - -static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) -{ - return HvCall1(HvCallCfgSetMinRuntimeMsChunks, chunks); -} - static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) { return HvCall0(HvCallCfgGetSystemPhysicalProcessors); @@ -141,14 +102,6 @@ static inline u64 HvCallCfg_getPhysicalP return HvCall2(HvCallCfgGetPhysicalProcessors, lp, qual); } -static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, - u16 hvLogicalProcIndex) -{ - return HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc, lp, - hvLogicalProcIndex); - -} - static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) { return HvCall1(HvCallCfgGetSharedPoolIndex, lp); @@ -164,15 +117,13 @@ static inline u64 HvCallCfg_getSharedPro static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { - u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); - return retVal; + return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); } static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) { - u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex, lp); - return retVal; + return HvCall1(HvCallCfgGetHostingLpIndex, lp); } #endif /* _HVCALLCFG_H */ diff -ruNp linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvLpConfig.h linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvLpConfig.h --- linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-02 16:21:09.000000000 +1000 +++ linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-02 16:59:16.000000000 +1000 @@ -40,127 +40,16 @@ static inline HvLpIndex HvLpConfig_getPr return itLpNaca.xPrimaryLpIndex; } -static inline HvLpIndex HvLpConfig_getLps(void) -{ - return HvCallCfg_getLps(); -} - -static inline HvLpIndexMap HvLpConfig_getActiveLpMap(void) -{ - return HvCallCfg_getActiveLpMap(); -} - -static inline u64 HvLpConfig_getSystemMsMegs(void) -{ - return HvCallCfg_getSystemMsChunks() / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getSystemMsChunks(void) -{ - return HvCallCfg_getSystemMsChunks(); -} - -static inline u64 HvLpConfig_getSystemMsPages(void) -{ - return HvCallCfg_getSystemMsChunks() * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) - / HVCHUNKSPERMEG; -} - static inline u64 HvLpConfig_getMsChunks(void) { return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur); } -static inline u64 HvLpConfig_getMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMinMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMinMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min); -} - -static inline u64 HvLpConfig_getMinMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMinRuntimeMsMegs(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMinRuntimeMsChunks(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()); -} - -static inline u64 HvLpConfig_getMinRuntimeMsPages(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMaxMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMaxMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max); -} - -static inline u64 HvLpConfig_getMaxMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getInitMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getInitMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init); -} - -static inline u64 HvLpConfig_getInitMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) - * HVPAGESPERCHUNK; -} - static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) { return HvCallCfg_getSystemPhysicalProcessors(); } -static inline u64 HvLpConfig_getSystemLogicalProcessors(void) -{ - return HvCallCfg_getSystemPhysicalProcessors() - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { return HvCallCfg_getNumProcsInSharedPool(sPI); @@ -172,13 +61,6 @@ static inline u64 HvLpConfig_getPhysical HvCallCfg_Cur); } -static inline u64 HvLpConfig_getLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Cur) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) { return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex()); @@ -190,57 +72,18 @@ static inline u64 HvLpConfig_getSharedPr HvCallCfg_Cur); } -static inline u64 HvLpConfig_getMinSharedProcUnits(void) -{ - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), - HvCallCfg_Min); -} - static inline u64 HvLpConfig_getMaxSharedProcUnits(void) { return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline u64 HvLpConfig_getMinPhysicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Min); -} - -static inline u64 HvLpConfig_getMinLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Min) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) { return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline u64 HvLpConfig_getMaxLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Max) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - -static inline u64 HvLpConfig_getInitPhysicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Init); -} - -static inline u64 HvLpConfig_getInitLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Init) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) { return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline()); @@ -252,37 +95,6 @@ static inline HvLpVirtualLanIndexMap HvL return HvCallCfg_getVirtualLanIndexMap(lp); } -static inline HvLpIndex HvLpConfig_getBusOwner(HvBusNumber busNumber) -{ - return HvCallCfg_getBusOwner(busNumber); -} - -static inline int HvLpConfig_isBusDedicated(HvBusNumber busNumber) -{ - return HvCallCfg_isBusDedicated(busNumber); -} - -static inline HvLpIndexMap HvLpConfig_getBusAllocation(HvBusNumber busNumber) -{ - return HvCallCfg_getBusAllocation(busNumber); -} - -/* returns the absolute real address of the load area */ -static inline u64 HvLpConfig_getLoadAddress(void) -{ - return itLpNaca.xLoadAreaAddr & 0x7fffffffffffffff; -} - -static inline u64 HvLpConfig_getLoadPages(void) -{ - return itLpNaca.xLoadAreaChunks * HVPAGESPERCHUNK; -} - -static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber) -{ - return (HvLpConfig_getBusOwner(busNumber) == HvLpConfig_getLpIndex()); -} - static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2) { -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/a3726c97/attachment.pgp From sfr at canb.auug.org.au Thu Jun 2 17:43:36 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 17:43:36 +1000 Subject: [PATCH] iSeries: remove HvCallCfg.h Message-ID: <20050602174336.536b7fbf.sfr@canb.auug.org.au> Hi all, Now that the only users of things in HvCallCfg.h are in HvLpConfig.h, merge in the bit we need and remove HvCallCfg.h. HvCallCfg.h | 129 ----------------------------------------------------------- HvLpConfig.h | 59 +++++++++++++++++++------- 2 files changed, 42 insertions(+), 146 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvCallCfg.h linus-iSeries-headers.4/include/asm-ppc64/iSeries/HvCallCfg.h --- linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvCallCfg.h 2005-06-02 17:08:25.000000000 +1000 +++ linus-iSeries-headers.4/include/asm-ppc64/iSeries/HvCallCfg.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,129 +0,0 @@ -/* - * HvCallCfg.h - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ -#ifndef _HVCALLCFG_H -#define _HVCALLCFG_H - -#include -#include - -enum HvCallCfg_ReqQual { - HvCallCfg_Cur = 0, - HvCallCfg_Init = 1, - HvCallCfg_Max = 2, - HvCallCfg_Min = 3 -}; - -#define HvCallCfgGetLps HvCallCfg + 0 -#define HvCallCfgGetActiveLpMap HvCallCfg + 1 -#define HvCallCfgGetLpVrmIndex HvCallCfg + 2 -#define HvCallCfgGetLpMinSupportedPlicVrmIndex HvCallCfg + 3 -#define HvCallCfgGetLpMinCompatablePlicVrmIndex HvCallCfg + 4 -#define HvCallCfgGetLpVrmName HvCallCfg + 5 -#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 -#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 -#define HvCallCfgGetSystemMsChunks HvCallCfg + 8 -#define HvCallCfgGetMsChunks HvCallCfg + 9 -#define HvCallCfgGetInteractivePercentage HvCallCfg + 10 -#define HvCallCfgIsBusDedicated HvCallCfg + 11 -#define HvCallCfgGetBusOwner HvCallCfg + 12 -#define HvCallCfgGetBusAllocation HvCallCfg + 13 -#define HvCallCfgGetBusUnitOwner HvCallCfg + 14 -#define HvCallCfgGetBusUnitAllocation HvCallCfg + 15 -#define HvCallCfgGetVirtualBusPool HvCallCfg + 16 -#define HvCallCfgGetBusUnitInterruptProc HvCallCfg + 17 -#define HvCallCfgGetConfiguredBusUnitsForIntProc HvCallCfg + 18 -#define HvCallCfgGetRioSanBusPool HvCallCfg + 19 -#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 -#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 -#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 -#define HvCallCfgRouter23 HvCallCfg + 23 -#define HvCallCfgRouter24 HvCallCfg + 24 -#define HvCallCfgRouter25 HvCallCfg + 25 -#define HvCallCfgRouter26 HvCallCfg + 26 -#define HvCallCfgRouter27 HvCallCfg + 27 -#define HvCallCfgGetMinRuntimeMsChunks HvCallCfg + 28 -#define HvCallCfgSetMinRuntimeMsChunks HvCallCfg + 29 -#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 -#define HvCallCfgGetLpExecutionMode HvCallCfg + 31 -#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 - -static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) -{ - return HvCall1(HvCallCfgGetBusOwner, busIndex); -} - -static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( - HvLpIndex lp) -{ - /* - * This is a new function in V5R1 so calls to this on older - * hypervisors will return -1 - */ - u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); - if (retVal == -1) - retVal = 0; - return retVal; -} - -static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetMsChunks, lp, qual); -} - -static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) -{ - return HvCall0(HvCallCfgGetSystemPhysicalProcessors); -} - -static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetPhysicalProcessors, lp, qual); -} - -static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) -{ - return HvCall1(HvCallCfgGetSharedPoolIndex, lp); - -} - -static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetSharedProcUnits, lp, qual); - -} - -static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) -{ - return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); - -} - -static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) -{ - return HvCall1(HvCallCfgGetHostingLpIndex, lp); -} - -#endif /* _HVCALLCFG_H */ diff -ruNp linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvLpConfig.h linus-iSeries-headers.4/include/asm-ppc64/iSeries/HvLpConfig.h --- linus-iSeries-headers.3/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-02 16:59:16.000000000 +1000 +++ linus-iSeries-headers.4/include/asm-ppc64/iSeries/HvLpConfig.h 2005-06-02 17:39:37.000000000 +1000 @@ -24,10 +24,26 @@ * to determine which resources should be allocated to each partition. */ -#include +#include #include #include +enum { + HvCallCfg_Cur = 0, + HvCallCfg_Init = 1, + HvCallCfg_Max = 2, + HvCallCfg_Min = 3 +}; + +#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 +#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 +#define HvCallCfgGetMsChunks HvCallCfg + 9 +#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 +#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 +#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 +#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 +#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 + extern HvLpIndex HvLpConfig_getLpIndex_outline(void); static inline HvLpIndex HvLpConfig_getLpIndex(void) @@ -42,72 +58,81 @@ static inline HvLpIndex HvLpConfig_getPr static inline u64 HvLpConfig_getMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur); + return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(), + HvCallCfg_Cur); } static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) { - return HvCallCfg_getSystemPhysicalProcessors(); + return HvCall0(HvCallCfgGetSystemPhysicalProcessors); } static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { - return HvCallCfg_getNumProcsInSharedPool(sPI); + return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); } static inline u64 HvLpConfig_getPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), HvCallCfg_Cur); } static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) { - return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex()); + return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex()); } static inline u64 HvLpConfig_getSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), HvCallCfg_Cur); } static inline u64 HvLpConfig_getMaxSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), HvCallCfg_Max); } static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( + HvLpIndex lp) { - return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline()); + /* + * This is a new function in V5R1 so calls to this on older + * hypervisors will return -1 + */ + u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); + if (retVal == -1) + retVal = 0; + return retVal; } -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( - HvLpIndex lp) +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) { - return HvCallCfg_getVirtualLanIndexMap(lp); + return HvLpConfig_getVirtualLanIndexMapForLp( + HvLpConfig_getLpIndex_outline()); } static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2) { HvLpVirtualLanIndexMap virtualLanIndexMap1 = - HvCallCfg_getVirtualLanIndexMap(lp1); + HvLpConfig_getVirtualLanIndexMapForLp(lp1); HvLpVirtualLanIndexMap virtualLanIndexMap2 = - HvCallCfg_getVirtualLanIndexMap(lp2); + HvLpConfig_getVirtualLanIndexMapForLp(lp2); return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); } static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) { - return HvCallCfg_getHostingLpIndex(lp); + return HvCall1(HvCallCfgGetHostingLpIndex, lp); } #endif /* _HVLPCONFIG_H */ -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/e01487ba/attachment.pgp From sfr at canb.auug.org.au Thu Jun 2 18:06:11 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 18:06:11 +1000 Subject: [PATCH] iSeries: cleanup ItLpQueue.h a bit Message-ID: <20050602180611.251140c8.sfr@canb.auug.org.au> Hi all, Just white space cleaups and move process_iSeries_events into its only caller. arch/ppc64/kernel/idle.c | 5 +++++ include/asm-ppc64/iSeries/ItLpQueue.h | 16 ++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.4/arch/ppc64/kernel/idle.c linus-iSeries-headers.5/arch/ppc64/kernel/idle.c --- linus-iSeries-headers.4/arch/ppc64/kernel/idle.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.5/arch/ppc64/kernel/idle.c 2005-06-02 18:03:04.000000000 +1000 @@ -42,6 +42,11 @@ static int (*idle_loop)(void); static unsigned long maxYieldTime = 0; static unsigned long minYieldTime = 0xffffffffffffffffUL; +static inline void process_iSeries_events(void) +{ + asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); +} + static void yield_shared_processor(void) { unsigned long tb; diff -ruNp linus-iSeries-headers.4/include/asm-ppc64/iSeries/ItLpQueue.h linus-iSeries-headers.5/include/asm-ppc64/iSeries/ItLpQueue.h --- linus-iSeries-headers.4/include/asm-ppc64/iSeries/ItLpQueue.h 2005-06-01 17:05:16.000000000 +1000 +++ linus-iSeries-headers.5/include/asm-ppc64/iSeries/ItLpQueue.h 2005-06-02 14:55:45.000000000 +1000 @@ -64,9 +64,9 @@ struct ItLpQueue { u8 xPlicStatus; // 0x01 DedicatedIo or DedicatedLp or NotUsed u16 xSlicLogicalProcIndex; // 0x02 Logical Proc Index for correlation u8 xPlicRsvd[12]; // 0x04 - char* xSlicCurEventPtr; // 0x10 - char* xSlicLastValidEventPtr; // 0x18 - char* xSlicEventStackPtr; // 0x20 + char *xSlicCurEventPtr; // 0x10 + char *xSlicLastValidEventPtr; // 0x18 + char *xSlicEventStackPtr; // 0x20 u8 xIndex; // 0x28 unique sequential index. u8 xSlicRsvd[3]; // 0x29-2b u32 xInUseWord; // 0x2C @@ -76,17 +76,9 @@ struct ItLpQueue { extern struct ItLpQueue xItLpQueue; -extern struct HvLpEvent * ItLpQueue_getNextLpEvent(struct ItLpQueue *); +extern struct HvLpEvent *ItLpQueue_getNextLpEvent(struct ItLpQueue *); extern int ItLpQueue_isLpIntPending(struct ItLpQueue *); extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *); extern void ItLpQueue_clearValid(struct HvLpEvent *); -static __inline__ void process_iSeries_events(void) -{ - __asm__ __volatile__ ( - " li 0,0x5555 \n\ - sc" - : : : "r0", "r3"); -} - #endif /* _ITLPQUEUE_H */ -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/2527f204/attachment.pgp From sfr at canb.auug.org.au Thu Jun 2 18:18:10 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 18:18:10 +1000 Subject: [PATCH] iSeries: remove some unused bits Message-ID: <20050602181810.10935e25.sfr@canb.auug.org.au> Hi all, This patch removes some unused bits from HvCall.h and some #includes from other files. Also includes ItLpQueue.h in paca.h in preference to a stub declaration of struct ItLpQueue. arch/ppc64/kernel/asm-offsets.c | 1 arch/ppc64/kernel/iSeries_pci.c | 1 arch/ppc64/kernel/mf.c | 1 arch/ppc64/kernel/rtc.c | 1 include/asm-ppc64/iSeries/HvCall.h | 84 ------------------------------------- include/asm-ppc64/paca.h | 2 6 files changed, 3 insertions(+), 87 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.5/arch/ppc64/kernel/asm-offsets.c linus-iSeries-headers.6/arch/ppc64/kernel/asm-offsets.c --- linus-iSeries-headers.5/arch/ppc64/kernel/asm-offsets.c 2005-05-20 09:03:13.000000000 +1000 +++ linus-iSeries-headers.6/arch/ppc64/kernel/asm-offsets.c 2005-06-02 15:50:28.000000000 +1000 @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.5/arch/ppc64/kernel/iSeries_pci.c linus-iSeries-headers.6/arch/ppc64/kernel/iSeries_pci.c --- linus-iSeries-headers.5/arch/ppc64/kernel/iSeries_pci.c 2005-06-02 16:16:36.000000000 +1000 +++ linus-iSeries-headers.6/arch/ppc64/kernel/iSeries_pci.c 2005-06-02 16:48:16.000000000 +1000 @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff -ruNp linus-iSeries-headers.5/arch/ppc64/kernel/mf.c linus-iSeries-headers.6/arch/ppc64/kernel/mf.c --- linus-iSeries-headers.5/arch/ppc64/kernel/mf.c 2005-05-26 10:44:08.000000000 +1000 +++ linus-iSeries-headers.6/arch/ppc64/kernel/mf.c 2005-06-02 14:59:25.000000000 +1000 @@ -40,7 +40,6 @@ #include #include #include -#include #include /* diff -ruNp linus-iSeries-headers.5/arch/ppc64/kernel/rtc.c linus-iSeries-headers.6/arch/ppc64/kernel/rtc.c --- linus-iSeries-headers.5/arch/ppc64/kernel/rtc.c 2005-06-02 16:18:54.000000000 +1000 +++ linus-iSeries-headers.6/arch/ppc64/kernel/rtc.c 2005-06-02 16:48:16.000000000 +1000 @@ -44,7 +44,6 @@ #include #include -#include extern int piranha_simulator; diff -ruNp linus-iSeries-headers.5/include/asm-ppc64/iSeries/HvCall.h linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvCall.h --- linus-iSeries-headers.5/include/asm-ppc64/iSeries/HvCall.h 2005-06-01 14:51:07.000000000 +1000 +++ linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvCall.h 2005-06-02 13:29:59.000000000 +1000 @@ -27,48 +27,6 @@ #include #include -/* -enum HvCall_ReturnCode -{ - HvCall_Good = 0, - HvCall_Partial = 1, - HvCall_NotOwned = 2, - HvCall_NotFreed = 3, - HvCall_UnspecifiedError = 4 -}; - -enum HvCall_TypeOfSIT -{ - HvCall_ReduceOnly = 0, - HvCall_Unconditional = 1 -}; - -enum HvCall_TypeOfYield -{ - HvCall_YieldTimed = 0, // Yield until specified time - HvCall_YieldToActive = 1, // Yield until all active procs have run - HvCall_YieldToProc = 2 // Yield until the specified processor has run -}; - -enum HvCall_InterruptMasks -{ - HvCall_MaskIPI = 0x00000001, - HvCall_MaskLpEvent = 0x00000002, - HvCall_MaskLpProd = 0x00000004, - HvCall_MaskTimeout = 0x00000008 -}; - -enum HvCall_VaryOffChunkRc -{ - HvCall_VaryOffSucceeded = 0, - HvCall_VaryOffWithdrawn = 1, - HvCall_ChunkInLoadArea = 2, - HvCall_ChunkInHPT = 3, - HvCall_ChunkNotAccessible = 4, - HvCall_ChunkInUse = 5 -}; -*/ - /* Type of yield for HvCallBaseYieldProcessor */ #define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ #define HvCall_YieldToActive 1 /* Yield until all active procs have run */ @@ -139,35 +97,12 @@ static inline void HvCall_setEnabledInte HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); } -static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) -{ - HvCall1(HvCallBaseClearLogBuffer, lpindex); -} - -static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) -{ - u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage, lpindex); - return retVal; -} - -static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) -{ - int retVal = HvCall1(HvCallBaseGetLogBufferFormat, lpindex); - return retVal; -} - -static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) -{ - u32 retVal = HvCall1(HvCallBaseGetLogBufferLength, lpindex); - return retVal; -} - -static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) +static inline void HvCall_setLogBufferFormatAndCodepage(int format, + u32 codePage) { HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); } -extern int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); static inline void HvCall_sendIPI(struct paca_struct *targetPaca) @@ -175,19 +110,4 @@ static inline void HvCall_sendIPI(struct HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); } -static inline void HvCall_terminateMachineSrc(void) -{ - HvCall0(HvCallBaseTerminateMachineSrc); -} - -static inline void HvCall_setDABR(unsigned long val) -{ - HvCall1(HvCallCcSetDABR, val); -} - -static inline void HvCall_setDebugBus(unsigned long val) -{ - HvCall1(HvCallBaseSetDebugBus, val); -} - #endif /* _HVCALL_H */ diff -ruNp linus-iSeries-headers.5/include/asm-ppc64/paca.h linus-iSeries-headers.6/include/asm-ppc64/paca.h --- linus-iSeries-headers.5/include/asm-ppc64/paca.h 2005-05-20 09:05:56.000000000 +1000 +++ linus-iSeries-headers.6/include/asm-ppc64/paca.h 2005-06-02 15:52:17.000000000 +1000 @@ -20,13 +20,13 @@ #include #include #include +#include #include register struct paca_struct *local_paca asm("r13"); #define get_paca() local_paca struct task_struct; -struct ItLpQueue; /* * Defines the layout of the paca. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/ddbfdacb/attachment.pgp From sfr at canb.auug.org.au Thu Jun 2 18:27:14 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Thu, 2 Jun 2005 18:27:14 +1000 Subject: [PATCH] iSeries: Message-ID: <20050602182714.76b28e7a.sfr@canb.auug.org.au> Hi all, Last of the cleanups for today :-) - don't have two defines for the same thing (HvMaxArchitectedLps and HvMaxArchitectedVirtualLans) - HvCallSc.h only needs linux/types.h - remove unused struct definition arch/ppc64/kernel/viopath.c | 4 +-- include/asm-ppc64/iSeries/HvCallSc.h | 34 ++++++++++++++++----------------- include/asm-ppc64/iSeries/HvTypes.h | 8 ++----- include/asm-ppc64/iSeries/ItVpdAreas.h | 6 ----- 4 files changed, 22 insertions(+), 30 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.6/arch/ppc64/kernel/viopath.c linus-iSeries-headers.7/arch/ppc64/kernel/viopath.c --- linus-iSeries-headers.6/arch/ppc64/kernel/viopath.c 2005-06-02 17:06:58.000000000 +1000 +++ linus-iSeries-headers.7/arch/ppc64/kernel/viopath.c 2005-06-02 18:09:32.000000000 +1000 @@ -485,7 +485,7 @@ int viopath_open(HvLpIndex remoteLp, int unsigned long flags; int tempNumAllocated; - if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid)) + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) return -EINVAL; subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; @@ -556,7 +556,7 @@ int viopath_close(HvLpIndex remoteLp, in int numOpen; struct alloc_parms parms; - if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid)) + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) return -EINVAL; subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; diff -ruNp linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvCallSc.h linus-iSeries-headers.7/include/asm-ppc64/iSeries/HvCallSc.h --- linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvCallSc.h 2005-06-01 15:46:19.000000000 +1000 +++ linus-iSeries-headers.7/include/asm-ppc64/iSeries/HvCallSc.h 2005-06-02 14:00:14.000000000 +1000 @@ -19,7 +19,7 @@ #ifndef _HVCALLSC_H #define _HVCALLSC_H -#include +#include #define HvCallBase 0x8000000000000000ul #define HvCallCc 0x8001000000000000ul @@ -30,22 +30,22 @@ #define HvCallSm 0x8007000000000000ul #define HvCallXm 0x8009000000000000ul -u64 HvCall0(u64); -u64 HvCall1(u64, u64); -u64 HvCall2(u64, u64, u64); -u64 HvCall3(u64, u64, u64, u64); -u64 HvCall4(u64, u64, u64, u64, u64); -u64 HvCall5(u64, u64, u64, u64, u64, u64); -u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); -u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); +extern u64 HvCall0(u64); +extern u64 HvCall1(u64, u64); +extern u64 HvCall2(u64, u64, u64); +extern u64 HvCall3(u64, u64, u64, u64); +extern u64 HvCall4(u64, u64, u64, u64, u64); +extern u64 HvCall5(u64, u64, u64, u64, u64, u64); +extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); -u64 HvCall0Ret16(u64, void *); -u64 HvCall1Ret16(u64, void *, u64); -u64 HvCall2Ret16(u64, void *, u64, u64); -u64 HvCall3Ret16(u64, void *, u64, u64, u64); -u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); -u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); -u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); -u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); +extern u64 HvCall0Ret16(u64, void *); +extern u64 HvCall1Ret16(u64, void *, u64); +extern u64 HvCall2Ret16(u64, void *, u64, u64); +extern u64 HvCall3Ret16(u64, void *, u64, u64, u64); +extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); +extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); +extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); #endif /* _HVCALLSC_H */ diff -ruNp linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvTypes.h linus-iSeries-headers.7/include/asm-ppc64/iSeries/HvTypes.h --- linus-iSeries-headers.6/include/asm-ppc64/iSeries/HvTypes.h 2005-06-01 16:45:03.000000000 +1000 +++ linus-iSeries-headers.7/include/asm-ppc64/iSeries/HvTypes.h 2005-06-02 14:15:29.000000000 +1000 @@ -40,14 +40,14 @@ typedef u64 HvIoToken; typedef u8 HvLpName[8]; typedef u32 HvIoId; typedef u64 HvRealMemoryIndex; -typedef u32 HvLpIndexMap; /* Must hold HvMaxArchitectedLps bits!!! */ +typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */ typedef u16 HvLpVrmIndex; typedef u32 HvXmGenerationId; typedef u8 HvLpBusPool; typedef u8 HvLpSharedPoolIndex; typedef u16 HvLpSharedProcUnitsX100; typedef u8 HvLpVirtualLanIndex; -typedef u16 HvLpVirtualLanIndexMap; /* Must hold HvMaxArchitectedVirtualLans bits!!! */ +typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */ typedef u16 HvBusNumber; /* Hypervisor Bus Number */ typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ typedef u8 HvAgentId; /* Hypervisor DevFn */ @@ -66,15 +66,13 @@ typedef u8 HvAgentId; /* Hypervisor DevF #define HVPAGESPERMEG 256 #define HVPAGESPERCHUNK 64 -#define HvMaxArchitectedLps ((HvLpIndex)HVMAXARCHITECTEDLPS) -#define HvMaxArchitectedVirtualLans ((HvLpVirtualLanIndex)16) #define HvLpIndexInvalid ((HvLpIndex)0xff) /* * Enums for the sub-components under PLIC * Used in HvCall and HvPrimaryCall */ -enum HvCallCompIds { +enum { HvCallCompId = 0, HvCallCpuCtlsCompId = 1, HvCallCfgCompId = 2, diff -ruNp linus-iSeries-headers.6/include/asm-ppc64/iSeries/ItVpdAreas.h linus-iSeries-headers.7/include/asm-ppc64/iSeries/ItVpdAreas.h --- linus-iSeries-headers.6/include/asm-ppc64/iSeries/ItVpdAreas.h 2005-06-02 16:22:09.000000000 +1000 +++ linus-iSeries-headers.7/include/asm-ppc64/iSeries/ItVpdAreas.h 2005-06-02 16:48:16.000000000 +1000 @@ -61,12 +61,6 @@ #define ItVpdAreasMaxSlotLabels 192 -struct SlicVpdAdrs { - u32 pad1; - void *vpdAddr; -}; - - struct ItVpdAreas { u32 xSlicDesc; // Descriptor 000-003 u16 xSlicSize; // Size of this control block 004-005 -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/8781e4e4/attachment.pgp From arnd at arndb.de Fri Jun 3 01:52:05 2005 From: arnd at arndb.de (Arnd Bergmann) Date: Thu, 2 Jun 2005 17:52:05 +0200 Subject: [PATCH] ppc64: Fix result code handling in prom_init In-Reply-To: <1117685497.31082.27.camel@gaston> References: <1117685497.31082.27.camel@gaston> Message-ID: <200506021752.06035.arnd@arndb.de> On Dunnersdag 02 Juni 2005 06:11, Benjamin Herrenschmidt wrote: > This patch reworks it all. Tested on g5, Maple, POWER3 and POWER5. Works on the Cell firmware as well, as expected. Thanks! Arnd <>< From xma at us.ibm.com Fri Jun 3 02:20:02 2005 From: xma at us.ibm.com (Shirley Ma) Date: Thu, 2 Jun 2005 09:20:02 -0700 Subject: get_cyles() In-Reply-To: Message-ID: Doesn't ppc64 supports get_cycles() correctly? I used below function to get_cycles(), it seems not right. t1 = get_cycles(); t2 = get_cycles(); t2-t1 is huge. static inline cycles_t get_cycles(void) { cycles_t ret; __asm__ __volatile__("mftb %0" : "=r" (ret) : ); return ret; } Shirley Ma IBM Linux Technology Center 15300 SW Koll Parkway Beaverton, OR 97006-6063 Phone(Fax): (503) 578-7638 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/382a94ab/attachment.htm From zwane at arm.linux.org.uk Fri Jun 3 05:42:44 2005 From: zwane at arm.linux.org.uk (Zwane Mwaikambo) Date: Thu, 2 Jun 2005 13:42:44 -0600 (MDT) Subject: get_cyles() In-Reply-To: References: Message-ID: On Thu, 2 Jun 2005, Shirley Ma wrote: > Doesn't ppc64 supports get_cycles() correctly? > I used below function to get_cycles(), it seems not right. > > t1 = get_cycles(); > t2 = get_cycles(); > > t2-t1 is huge. > > static inline cycles_t get_cycles(void) > { > cycles_t ret; > > __asm__ __volatile__("mftb %0" : "=r" (ret) : ); > return ret; > } Conjecture: Timebase is 33MHz (so it's slow compared to processor instruction retiring), there is a very small gap between t2 and t1 sampling time delta wise and it may go backwards(?). What are the actual numbers? Zwane From xma at us.ibm.com Fri Jun 3 07:18:27 2005 From: xma at us.ibm.com (Shirley Ma) Date: Thu, 2 Jun 2005 14:18:27 -0700 Subject: get_cyles() In-Reply-To: Message-ID: I found the reason. The application(32bit) printed unsigned long long, the get_cycles() returns unsigned long. Thanks Shirley Ma IBM Linux Technology Center 15300 SW Koll Parkway Beaverton, OR 97006-6063 Phone(Fax): (503) 578-7638 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/1e080e66/attachment.htm From gerald.vanbaren at smiths-aerospace.com Fri Jun 3 06:08:09 2005 From: gerald.vanbaren at smiths-aerospace.com (Jerry Van Baren) Date: Thu, 2 Jun 2005 16:08:09 -0400 Subject: get_cyles() In-Reply-To: References: Message-ID: <429F6729.5070202@smiths-aerospace.com> Shirley Ma wrote: > > Doesn't ppc64 supports get_cycles() correctly? > I used below function to get_cycles(), it seems not right. > > t1 = get_cycles(); > t2 = get_cycles(); > > t2-t1 is huge. > > static inline cycles_t get_cycles(void) > { > cycles_t ret; > > __asm__ __volatile__("mftb %0" : "=r" (ret) : ); > return ret; > } > > Shirley Ma > IBM Linux Technology Center > 15300 SW Koll Parkway > Beaverton, OR 97006-6063 > Phone(Fax): (503) 578-7638 Is (t2-t1) (a) _always_ huge or (b) only sometimes huge? If (a), are you sure t1 and t2 are executing in the written order? The compiler may be re-ordering the instructions on you. Use objdump -S to disassemble the object file (or executable). If (b), you are getting burned by carry out of the time base lower register. Every 2^32 counts, the timebase (lower) register will wrap around from 0xFFFFFFFF to 0x00000000. If the wrap occurs between reading t1 and t2, you will get a very large jump. Another possiblility for (b) is that you are getting an interrupt between reading t1 and t2, so your delta will include the interrupt handling time and potentially more... if your task is pre-empted due to the interrupt, the time delta will be (relatively speaking) very large. This is actually the most likely scenario in my mind. gvb From ntl at pobox.com Fri Jun 3 08:15:09 2005 From: ntl at pobox.com (Nathan Lynch) Date: Thu, 2 Jun 2005 17:15:09 -0500 Subject: [PATCH] fix slab corruption during ipr probe Message-ID: <20050602221509.GA11355@otto> Hi- With CONFIG_DEBUG_SLAB=y I see slab corruption messages during boot on pSeries machines with IPR adapters with any 2.6.12-rc kernel. The change which seems to have introduced the problem is "SCSI: revamp target scanning routines" and may be found at: http://marc.theaimsgroup.com/?l=bk-commits-head&m=111093946426333&w=2 In order to revert that in a 2.6.12-rc1 tree, I had to revert "target code updates to support scanned targets" first: http://marc.theaimsgroup.com/?l=bk-commits-head&m=111094132524649&w=2 With both patches reverted, the corruption messages go away. ipr: IBM Power RAID SCSI Device Driver version: 2.0.13 (February 21, 2005) ipr 0001:d0:01.0: Found IOA with IRQ: 167 ipr 0001:d0:01.0: Starting IOA initialization sequence. ipr 0001:d0:01.0: Adapter firmware version: 020A005C ipr 0001:d0:01.0: IOA initialized. scsi0 : IBM 570B Storage Adapter Vendor: IBM Model: VSBPD4E1 U4SCSI Rev: 4770 Type: Enclosure ANSI SCSI revision: 02 Vendor: IBM H0 Model: HUS103036FL3800 Rev: RPQF Type: Direct-Access ANSI SCSI revision: 04 Vendor: IBM H0 Model: HUS103036FL3800 Rev: RPQF Type: Direct-Access ANSI SCSI revision: 04 Vendor: IBM H0 Model: HUS103036FL3800 Rev: RPQF Type: Direct-Access ANSI SCSI revision: 04 Vendor: IBM H0 Model: HUS103036FL3800 Rev: RPQF Type: Direct-Access ANSI SCSI revision: 04 Vendor: IBM Model: VSBPD4E1 U4SCSI Rev: 4770 Type: Enclosure ANSI SCSI revision: 02 Slab corruption: start=c0000001e8de5268, len=512 Redzone: 0x5a2cf071/0x5a2cf071. Last user: [](.scsi_target_dev_release+0x28/0x50) 080: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6a Prev obj: start=c0000001e8de5050, len=512 Redzone: 0x5a2cf071/0x5a2cf071. Last user: [<0000000000000000>](0x0) 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b Next obj: start=c0000001e8de5480, len=512 Redzone: 0x170fc2a5/0x170fc2a5. Last user: [](.as_init_queue+0x5c/0x228) 000: c0 00 00 01 e8 83 26 08 00 00 00 00 00 00 00 00 010: 00 00 00 00 00 00 00 00 c0 00 00 01 e8 de 54 98 Slab corruption: start=c0000001e8de5268, len=512 Redzone: 0x5a2cf071/0x5a2cf071. Last user: [](.scsi_target_dev_release+0x28/0x50) 080: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6a Prev obj: start=c0000001e8de5050, len=512 Redzone: 0x5a2cf071/0x5a2cf071. Last user: [<0000000000000000>](0x0) 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b Next obj: start=c0000001e8de5480, len=512 Redzone: 0x170fc2a5/0x170fc2a5. Last user: [](.as_init_queue+0x5c/0x228) 000: c0 00 00 01 e8 83 26 08 00 00 00 00 00 00 00 00 010: 00 00 00 00 00 00 00 00 c0 00 00 01 e8 de 54 98 ... I did some digging and the problem seems to be a refcounting issue in __scsi_add_device. The target gets freed in scsi_target_reap, and then __scsi_add_device tries to do another device_put on it. I'm not sure whether other users of __scsi_add_device are affected by this. This patch works for me (tm); is it correct? Signed-off-by: Nathan Lynch Index: linux-2.6.12-rc5/drivers/scsi/scsi_scan.c =================================================================== --- linux-2.6.12-rc5.orig/drivers/scsi/scsi_scan.c +++ linux-2.6.12-rc5/drivers/scsi/scsi_scan.c @@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(st if (!starget) return ERR_PTR(-ENOMEM); + get_device(&starget->dev); down(&shost->scan_mutex); res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); if (res != SCSI_SCAN_LUN_PRESENT) From utz.bacher at de.ibm.com Fri Jun 3 09:33:57 2005 From: utz.bacher at de.ibm.com (Utz Bacher) Date: Fri, 3 Jun 2005 01:33:57 +0200 (CEST) Subject: [PATCH 3/8] ppc64: add a watchdog driver for rtas Message-ID: Nathan, Arnd, Nathan Lynch wrote: > Arnd Bergmann wrote: > > +static volatile int wdrtas_miscdev_open = 0; > ... > > +static int > > +wdrtas_open(struct inode *inode, struct file *file) > > +{ > > + /* only open once */ > > + if (xchg(&wdrtas_miscdev_open,1)) > > + return -EBUSY; > > The volatile and xchg strike me as an obscure method for ensuring only > one process at a time can open this file. Any reason a semaphore > couldn't be used? [...] > > + printk("wdrtas: got unexpected close. Watchdog " > > + "not stopped.\n"); > > printk's need a valid log level specified. There are several in this > file that lack them. the following patch fixes the issues the two of you had: now printks have a proper log level specified and atomic variables are used to prevent concurrent access to the watchdog file. Thanks, Utz :wq Add a watchdog using the RTAS OS surveillance service. This is provided as a simpler alternative to rtasd. The added value is that it works with standard watchdog client programs and can therefore also do user space monitoring. On BPA, rtasd is not really useful because the hardware does not have much to report with event-scan. The driver should also work on other platforms that support the OS surveillance RTAS calls. Signed-off-by: Utz Bacher diff -ruN linux-2.6.12-rc5.orig/drivers/char/watchdog/Kconfig linux-2.6.12-rc5/drivers/char/watchdog/Kconfig --- linux-2.6.12-rc5.orig/drivers/char/watchdog/Kconfig 2005-06-03 00:33:32.679342588 +0200 +++ linux-2.6.12-rc5/drivers/char/watchdog/Kconfig 2005-06-03 00:34:20.193419032 +0200 @@ -414,6 +414,16 @@ machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +# ppc64 RTAS watchdog +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on WATCHDOG && PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # # ISA-based Watchdog Cards # diff -ruN linux-2.6.12-rc5.orig/drivers/char/watchdog/Makefile linux-2.6.12-rc5/drivers/char/watchdog/Makefile --- linux-2.6.12-rc5.orig/drivers/char/watchdog/Makefile 2005-06-03 00:33:32.679342588 +0200 +++ linux-2.6.12-rc5/drivers/char/watchdog/Makefile 2005-06-03 00:34:20.194419404 +0200 @@ -33,6 +33,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # Only one watchdog can succeed. We probe the hardware watchdog # drivers first, then the softdog driver. This means if your hardware diff -ruN linux-2.6.12-rc5.orig/drivers/char/watchdog/wdrtas.c linux-2.6.12-rc5/drivers/char/watchdog/wdrtas.c --- linux-2.6.12-rc5.orig/drivers/char/watchdog/wdrtas.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.12-rc5/drivers/char/watchdog/wdrtas.c 2005-06-03 00:34:31.886208108 +0200 @@ -0,0 +1,696 @@ +/* + * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as + * RTAS calls are available + */ + +/* + * RTAS watchdog driver + * + * (C) Copyright IBM Corp. 2005 + * device driver to exploit watchdog RTAS functions + * + * Authors : Utz Bacher + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define WDRTAS_MAGIC_CHAR 42 +#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ + WDIOF_MAGICCLOSE) + +MODULE_AUTHOR("Utz Bacher "); +MODULE_DESCRIPTION("RTAS watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_ALIAS_MISCDEV(TEMP_MINOR); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int wdrtas_nowayout = 1; +#else +static int wdrtas_nowayout = 0; +#endif + +static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); +static char wdrtas_expect_close = 0; + +static int wdrtas_interval; + +#define WDRTAS_THERMAL_SENSOR 3 +static int wdrtas_token_get_sensor_state; +#define WDRTAS_SURVEILLANCE_IND 9000 +static int wdrtas_token_set_indicator; +#define WDRTAS_SP_SPI 28 +static int wdrtas_token_get_sp; +static int wdrtas_token_event_scan; + +#define WDRTAS_DEFAULT_INTERVAL 300 + +#define WDRTAS_LOGBUFFER_LEN 128 +static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; + + +/*** watchdog access functions */ + +/** + * wdrtas_set_interval - sets the watchdog interval + * @interval: new interval + * + * returns 0 on success, <0 on failures + * + * wdrtas_set_interval sets the watchdog keepalive interval by calling the + * RTAS function set-indicator (surveillance). The unit of interval is + * seconds. + */ +static int +wdrtas_set_interval(int interval) +{ + long result; + static int print_msg = 10; + + /* rtas uses minutes */ + interval = (interval + 59) / 60; + + result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, + WDRTAS_SURVEILLANCE_IND, 0, interval); + if ( (result < 0) && (print_msg) ) { + printk(KERN_ERR "wdrtas: setting the watchdog to %i " + "timeout failed: %li\n", interval, result); + print_msg--; + } + + return result; +} + +/** + * wdrtas_get_interval - returns the current watchdog interval + * @fallback_value: value (in seconds) to use, if the RTAS call fails + * + * returns the interval + * + * wdrtas_get_interval returns the current watchdog keepalive interval + * as reported by the RTAS function ibm,get-system-parameter. The unit + * of the return value is seconds. + */ +static int +wdrtas_get_interval(int fallback_value) +{ + long result; + char value[4]; + + result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, + WDRTAS_SP_SPI, (void *)__pa(&value), 4); + if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) || + (result < 0) ) { + printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " + "timeout (%li). Continuing\n", result); + return fallback_value; + } + + /* rtas uses minutes */ + return ((int)value[2]) * 60; +} + +/** + * wdrtas_timer_start - starts watchdog + * + * wdrtas_timer_start starts the watchdog by calling the RTAS function + * set-interval (surveillance) + */ +static void +wdrtas_timer_start(void) +{ + wdrtas_set_interval(wdrtas_interval); +} + +/** + * wdrtas_timer_stop - stops watchdog + * + * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function + * set-interval (surveillance) + */ +static void +wdrtas_timer_stop(void) +{ + wdrtas_set_interval(0); +} + +/** + * wdrtas_log_scanned_event - logs an event we received during keepalive + * + * wdrtas_log_scanned_event prints a message to the log buffer dumping + * the results of the last event-scan call + */ +static void +wdrtas_log_scanned_event(void) +{ + int i; + + for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16) + printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), + wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], + wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], + wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], + wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], + wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], + wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], + wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], + wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); +} + +/** + * wdrtas_timer_keepalive - resets watchdog timer to keep system alive + * + * wdrtas_timer_keepalive restarts the watchdog timer by calling the + * RTAS function event-scan and repeats these calls as long as there are + * events available. All events will be dumped. + */ +static void +wdrtas_timer_keepalive(void) +{ + long result; + + do { + result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL, + RTAS_EVENT_SCAN_ALL_EVENTS, 0, + (void *)__pa(wdrtas_logbuffer), + WDRTAS_LOGBUFFER_LEN); + if (result < 0) + printk(KERN_ERR "wdrtas: event-scan failed: %li\n", + result); + if (result == 0) + wdrtas_log_scanned_event(); + } while (result == 0); +} + +/** + * wdrtas_get_temperature - returns current temperature + * + * returns temperature or <0 on failures + * + * wdrtas_get_temperature returns the current temperature in Fahrenheit. It + * uses the RTAS call get-sensor-state, token 3 to do so + */ +static int +wdrtas_get_temperature(void) +{ + long result; + int temperature = 0; + + result = rtas_call(wdrtas_token_get_sensor_state, 2, 2, + (void *)__pa(&temperature), + WDRTAS_THERMAL_SENSOR, 0); + + if (result < 0) + printk(KERN_WARNING "wdrtas: reading the thermal sensor " + "faild: %li\n", result); + else + temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */ + + return temperature; +} + +/** + * wdrtas_get_status - returns the status of the watchdog + * + * returns a bitmask of defines WDIOF_... as defined in + * include/linux/watchdog.h + */ +static int +wdrtas_get_status(void) +{ + return 0; /* TODO */ +} + +/** + * wdrtas_get_boot_status - returns the reason for the last boot + * + * returns a bitmask of defines WDIOF_... as defined in + * include/linux/watchdog.h, indicating why the watchdog rebooted the system + */ +static int +wdrtas_get_boot_status(void) +{ + return 0; /* TODO */ +} + +/*** watchdog API and operations stuff */ + +/* wdrtas_write - called when watchdog device is written to + * @file: file structure + * @buf: user buffer with data + * @len: amount to data written + * @ppos: position in file + * + * returns the number of successfully processed characters, which is always + * the number of bytes passed to this function + * + * wdrtas_write processes all the data given to it and looks for the magic + * character 'V'. This character allows the watchdog device to be closed + * properly. + */ +static ssize_t +wdrtas_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + int i; + char c; + + if (!len) + goto out; + + if (!wdrtas_nowayout) { + wdrtas_expect_close = 0; + /* look for 'V' */ + for (i = 0; i < len; i++) { + if (get_user(c, buf + i)) + return -EFAULT; + /* allow to close device */ + if (c == 'V') + wdrtas_expect_close = WDRTAS_MAGIC_CHAR; + } + } + + wdrtas_timer_keepalive(); + +out: + return len; +} + +/** + * wdrtas_ioctl - ioctl function for the watchdog device + * @inode: inode structure + * @file: file structure + * @cmd: command for ioctl + * @arg: argument pointer + * + * returns 0 on success, <0 on failure + * + * wdrtas_ioctl implements the watchdog API ioctls + */ +static int +wdrtas_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int __user *argp = (void *)arg; + int i; + static struct watchdog_info wdinfo = { + .options = WDRTAS_SUPPORTED_MASK, + .firmware_version = 0, + .identity = "wdrtas" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &wdinfo, sizeof(wdinfo))) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + i = wdrtas_get_status(); + return put_user(i, argp); + + case WDIOC_GETBOOTSTATUS: + i = wdrtas_get_boot_status(); + return put_user(i, argp); + + case WDIOC_GETTEMP: + if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) + return -EOPNOTSUPP; + + i = wdrtas_get_temperature(); + return put_user(i, argp); + + case WDIOC_SETOPTIONS: + if (get_user(i, argp)) + return -EFAULT; + if (i & WDIOS_DISABLECARD) + wdrtas_timer_stop(); + if (i & WDIOS_ENABLECARD) { + wdrtas_timer_keepalive(); + wdrtas_timer_start(); + } + if (i & WDIOS_TEMPPANIC) { + /* not implemented. Done by H8 */ + } + return 0; + + case WDIOC_KEEPALIVE: + wdrtas_timer_keepalive(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(i, argp)) + return -EFAULT; + + if (wdrtas_set_interval(i)) + return -EINVAL; + + wdrtas_timer_keepalive(); + + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) + wdrtas_interval = i; + else + wdrtas_interval = wdrtas_get_interval(i); + /* fallthrough */ + + case WDIOC_GETTIMEOUT: + return put_user(wdrtas_interval, argp); + + default: + return -ENOIOCTLCMD; + } +} + +/** + * wdrtas_open - open function of watchdog device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success, -EBUSY if the file has been opened already, <0 on + * other failures + * + * function called when watchdog device is opened + */ +static int +wdrtas_open(struct inode *inode, struct file *file) +{ + /* only open once */ + if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { + atomic_dec(&wdrtas_miscdev_open); + return -EBUSY; + } + + wdrtas_timer_start(); + wdrtas_timer_keepalive(); + + return nonseekable_open(inode, file); +} + +/** + * wdrtas_close - close function of watchdog device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success + * + * close function. Always succeeds + */ +static int +wdrtas_close(struct inode *inode, struct file *file) +{ + /* only stop watchdog, if this was announced using 'V' before */ + if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) + wdrtas_timer_stop(); + else { + printk(KERN_WARNING "wdrtas: unexpected close. Watchdog " + "not stopped.\n"); + wdrtas_timer_keepalive(); + } + + wdrtas_expect_close = 0; + atomic_dec(&wdrtas_miscdev_open); + return 0; +} + +/** + * wdrtas_temp_read - gives back the temperature in fahrenheit + * @file: file structure + * @buf: user buffer + * @count: number of bytes to be read + * @ppos: position in file + * + * returns always 1 or -EFAULT in case of user space copy failures, <0 on + * other failures + * + * wdrtas_temp_read gives the temperature to the users by copying this + * value as one byte into the user space buffer. The unit is Fahrenheit... + */ +static ssize_t +wdrtas_temp_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int temperature = 0; + + temperature = wdrtas_get_temperature(); + if (temperature < 0) + return temperature; + + if (copy_to_user(buf, &temperature, 1)) + return -EFAULT; + + return 1; +} + +/** + * wdrtas_temp_open - open function of temperature device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success, <0 on failure + * + * function called when temperature device is opened + */ +static int +wdrtas_temp_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +/** + * wdrtas_temp_close - close function of temperature device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success + * + * close function. Always succeeds + */ +static int +wdrtas_temp_close(struct inode *inode, struct file *file) +{ + return 0; +} + +/** + * wdrtas_reboot - reboot notifier function + * @nb: notifier block structure + * @code: reboot code + * @ptr: unused + * + * returns NOTIFY_DONE + * + * wdrtas_reboot stops the watchdog in case of a reboot + */ +static int +wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr) +{ + if ( (code==SYS_DOWN) || (code==SYS_HALT) ) + wdrtas_timer_stop(); + + return NOTIFY_DONE; +} + +/*** initialization stuff */ + +static struct file_operations wdrtas_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wdrtas_write, + .ioctl = wdrtas_ioctl, + .open = wdrtas_open, + .release = wdrtas_close, +}; + +static struct miscdevice wdrtas_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdrtas_fops, +}; + +static struct file_operations wdrtas_temp_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = wdrtas_temp_read, + .open = wdrtas_temp_open, + .release = wdrtas_temp_close, +}; + +static struct miscdevice wdrtas_tempdev = { + .minor = TEMP_MINOR, + .name = "temperature", + .fops = &wdrtas_temp_fops, +}; + +static struct notifier_block wdrtas_notifier = { + .notifier_call = wdrtas_reboot, +}; + +/** + * wdrtas_get_tokens - reads in RTAS tokens + * + * returns 0 on succes, <0 on failure + * + * wdrtas_get_tokens reads in the tokens for the RTAS calls used in + * this watchdog driver. It tolerates, if "get-sensor-state" and + * "ibm,get-system-parameter" are not available. + */ +static int +wdrtas_get_tokens(void) +{ + wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); + if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { + printk(KERN_WARNING "wdrtas: couldn't get token for " + "get-sensor-state. Trying to continue without " + "temperature support.\n"); + } + + wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter"); + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) { + printk(KERN_WARNING "wdrtas: couldn't get token for " + "ibm,get-system-parameter. Trying to continue with " + "a default timeout value of %i seconds.\n", + WDRTAS_DEFAULT_INTERVAL); + } + + wdrtas_token_set_indicator = rtas_token("set-indicator"); + if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "wdrtas: couldn't get token for " + "set-indicator. Terminating watchdog code.\n"); + return -EIO; + } + + wdrtas_token_event_scan = rtas_token("event-scan"); + if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "wdrtas: couldn't get token for event-scan. " + "Terminating watchdog code.\n"); + return -EIO; + } + + return 0; +} + +/** + * wdrtas_unregister_devs - unregisters the misc dev handlers + * + * wdrtas_register_devs unregisters the watchdog and temperature watchdog + * misc devs + */ +static void +wdrtas_unregister_devs(void) +{ + misc_deregister(&wdrtas_miscdev); + if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) + misc_deregister(&wdrtas_tempdev); +} + +/** + * wdrtas_register_devs - registers the misc dev handlers + * + * returns 0 on succes, <0 on failure + * + * wdrtas_register_devs registers the watchdog and temperature watchdog + * misc devs + */ +static int +wdrtas_register_devs(void) +{ + int result; + + result = misc_register(&wdrtas_miscdev); + if (result) { + printk(KERN_ERR "wdrtas: couldn't register watchdog misc " + "device. Terminating watchdog code.\n"); + return result; + } + + if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) { + result = misc_register(&wdrtas_tempdev); + if (result) { + printk(KERN_WARNING "wdrtas: couldn't register " + "watchdog temperature misc device. Continuing " + "without temperature support.\n"); + wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE; + } + } + + return 0; +} + +/** + * wdrtas_init - init function of the watchdog driver + * + * returns 0 on succes, <0 on failure + * + * registers the file handlers and the reboot notifier + */ +static int __init +wdrtas_init(void) +{ + if (wdrtas_get_tokens()) + return -ENODEV; + + if (wdrtas_register_devs()) + return -ENODEV; + + if (register_reboot_notifier(&wdrtas_notifier)) { + printk(KERN_ERR "wdrtas: could not register reboot notifier. " + "Terminating watchdog code.\n"); + wdrtas_unregister_devs(); + return -ENODEV; + } + + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) + wdrtas_interval = WDRTAS_DEFAULT_INTERVAL; + else + wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL); + + return 0; +} + +/** + * wdrtas_exit - exit function of the watchdog driver + * + * unregisters the file handlers and the reboot notifier + */ +static void __exit +wdrtas_exit(void) +{ + if (!wdrtas_nowayout) + wdrtas_timer_stop(); + + wdrtas_unregister_devs(); + + unregister_reboot_notifier(&wdrtas_notifier); +} + +module_init(wdrtas_init); +module_exit(wdrtas_exit); From benh at kernel.crashing.org Fri Jun 3 17:18:24 2005 From: benh at kernel.crashing.org (Benjamin Herrenschmidt) Date: Fri, 03 Jun 2005 17:18:24 +1000 Subject: Booting the linux-ppc64 kernel & flattened device tree v0.4 In-Reply-To: <1117614484.19020.27.camel@gaston> References: <1117614390.19020.24.camel@gaston> <1117614484.19020.27.camel@gaston> Message-ID: <1117783104.31082.151.camel@gaston> On Wed, 2005-06-01 at 18:28 +1000, Benjamin Herrenschmidt wrote: > Here is the kernel patch. It applies on top of the various prom_init.c > bug fixes that I already posted today on the linuxppc-dev & > linuxppc64-dev lists (those will be in the next -mm and maybe in > 2.6.12). > > This patch is intended to hit upstream by 2.6.13 Ok, the patch I posted with version 0.4 implementing version 0x10 of the format was broken, here is a fixed version against current linus "git" as of today: Index: linux-work/arch/ppc64/kernel/prom_init.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-06-03 16:52:28.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom_init.c 2005-06-03 16:58:01.000000000 +1000 @@ -1534,7 +1534,8 @@ */ #define MAX_PROPERTY_NAME 64 -static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, +static void __init scan_dt_build_strings(phandle node, + unsigned long *mem_start, unsigned long *mem_end) { unsigned long offset = reloc_offset(); @@ -1547,16 +1548,21 @@ /* get and store all property names */ prev_name = RELOC(""); for (;;) { - int rc; - /* 64 is max len of name including nul. */ namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); - rc = call_prom("nextprop", 3, 1, node, prev_name, namep); - if (rc != 1) { + if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; } + + /* skip "name" */ + if (strcmp(namep, RELOC("name")) == 0) { + *mem_start = (unsigned long)namep; + prev_name = RELOC("name"); + continue; + } + /* get/create string entry */ soff = dt_find_string(namep); if (soff != 0) { *mem_start = (unsigned long)namep; @@ -1571,7 +1577,7 @@ /* do all our children */ child = call_prom("child", 1, 1, node); - while (child != (phandle)0) { + while (child != 0) { scan_dt_build_strings(child, mem_start, mem_end); child = call_prom("peer", 1, 1, child); } @@ -1580,16 +1586,13 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { - int l, align; phandle child; - char *namep, *prev_name, *sstart, *p, *ep; + char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; unsigned long soff; unsigned char *valp; unsigned long offset = reloc_offset(); - char pname[MAX_PROPERTY_NAME]; - char *path; - - path = RELOC(prom_scratch); + static char pname[MAX_PROPERTY_NAME]; + int l; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); @@ -1599,23 +1602,33 @@ namep, *mem_end - *mem_start); if (l >= 0) { /* Didn't fit? Get more room. */ - if (l+1 > *mem_end - *mem_start) { + if ((l+1) > (*mem_end - *mem_start)) { namep = make_room(mem_start, mem_end, l+1, 1); call_prom("package-to-path", 3, 1, node, namep, l); } namep[l] = '\0'; + /* Fixup an Apple bug where they have bogus \0 chars in the * middle of the path in some properties */ for (p = namep, ep = namep + l; p < ep; p++) if (*p == '\0') { memmove(p, p+1, ep - p); - ep--; l--; + ep--; l--; p--; } - *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); + + /* now try to extract the unit name in that mess */ + for (p = namep, lp = NULL; *p; p++) + if (*p == '/') + lp = p + 1; + if (lp != NULL) + memmove(namep, lp, strlen(lp) + 1); + *mem_start = _ALIGN(((unsigned long) namep) + + strlen(namep) + 1, 4); } /* get it again for debugging */ + path = RELOC(prom_scratch); memset(path, 0, PROM_SCRATCH_SIZE); call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); @@ -1623,23 +1636,27 @@ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { - int rc; - - rc = call_prom("nextprop", 3, 1, node, prev_name, pname); - if (rc != 1) + if (call_prom("nextprop", 3, 1, node, prev_name, + RELOC(pname)) != 1) break; + /* skip "name" */ + if (strcmp(RELOC(pname), RELOC("name")) == 0) { + prev_name = RELOC("name"); + continue; + } + /* find string offset */ - soff = dt_find_string(pname); + soff = dt_find_string(RELOC(pname)); if (soff == 0) { - prom_printf("WARNING: Can't find string index for <%s>, node %s\n", - pname, path); + prom_printf("WARNING: Can't find string index for" + " <%s>, node %s\n", RELOC(pname), path); break; } prev_name = sstart + soff; /* get length */ - l = call_prom("getproplen", 2, 1, node, pname); + l = call_prom("getproplen", 2, 1, node, RELOC(pname)); /* sanity checks */ if (l == PROM_ERROR) @@ -1648,7 +1665,7 @@ prom_printf("WARNING: ignoring large property "); /* It seems OF doesn't null-terminate the path :-( */ prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", pname, l); + prom_printf("%s length 0x%x\n", RELOC(pname), l); continue; } @@ -1658,17 +1675,16 @@ dt_push_token(soff, mem_start, mem_end); /* push property content */ - align = (l >= 8) ? 8 : 4; - valp = make_room(mem_start, mem_end, l, align); - call_prom("getprop", 4, 1, node, pname, valp, l); + valp = make_room(mem_start, mem_end, l, 4); + call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); *mem_start = _ALIGN(*mem_start, 4); } /* Add a "linux,phandle" property. */ soff = dt_find_string(RELOC("linux,phandle")); if (soff == 0) - prom_printf("WARNING: Can't find string index for " - " node %s\n", path); + prom_printf("WARNING: Can't find string index for" + " node %s\n", path); else { dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(4, mem_start, mem_end); @@ -1679,7 +1695,7 @@ /* do all our children */ child = call_prom("child", 1, 1, node); - while (child != (phandle)0) { + while (child != 0) { scan_dt_build_struct(child, mem_start, mem_end); child = call_prom("peer", 1, 1, child); } @@ -1718,7 +1734,8 @@ /* Build header and make room for mem rsv map */ mem_start = _ALIGN(mem_start, 4); - hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); + hdr = make_room(&mem_start, &mem_end, + sizeof(struct boot_param_header), 4); RELOC(dt_header_start) = (unsigned long)hdr; rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); @@ -1731,11 +1748,11 @@ namep = make_room(&mem_start, &mem_end, 16, 1); strcpy(namep, RELOC("linux,phandle")); mem_start = (unsigned long)namep + strlen(namep) + 1; - RELOC(dt_string_end) = mem_start; /* Build string array */ prom_printf("Building dt strings...\n"); scan_dt_build_strings(root, &mem_start, &mem_end); + RELOC(dt_string_end) = mem_start; /* Build structure */ mem_start = PAGE_ALIGN(mem_start); @@ -1750,9 +1767,11 @@ hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); hdr->version = OF_DT_VERSION; - hdr->last_comp_version = 1; + /* Version 16 is not backward compatible */ + hdr->last_comp_version = 0x10; /* Reserve the whole thing and copy the reserve map in, we * also bump mem_reserve_cnt to cause further reservations to @@ -1808,6 +1827,9 @@ /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) return; + + prom_printf("fixing up bogus interrupts for u3 i2c...\n"); + /* interrupt on this revision of u3 is number 0 and level */ interrupts[0] = 0; interrupts[1] = 1; Index: linux-work/arch/ppc64/kernel/prom.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/prom.c 2005-05-09 14:44:32.000000000 +1000 +++ linux-work/arch/ppc64/kernel/prom.c 2005-06-03 16:58:01.000000000 +1000 @@ -625,8 +625,8 @@ static inline char *find_flat_dt_string(u32 offset) { - return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings - + offset; + return ((char *)initial_boot_params) + + initial_boot_params->off_dt_strings + offset; } /** @@ -635,26 +635,33 @@ * unflatten the tree */ static int __init scan_flat_dt(int (*it)(unsigned long node, - const char *full_path, void *data), + const char *uname, int depth, + void *data), void *data) { unsigned long p = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; int rc = 0; + int depth = -1; do { u32 tag = *((u32 *)p); char *pathp; p += 4; - if (tag == OF_DT_END_NODE) + if (tag == OF_DT_END_NODE) { + depth --; + continue; + } + if (tag == OF_DT_NOP) continue; if (tag == OF_DT_END) break; if (tag == OF_DT_PROP) { u32 sz = *((u32 *)p); p += 8; - p = _ALIGN(p, sz >= 8 ? 8 : 4); + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); p += sz; p = _ALIGN(p, 4); continue; @@ -664,9 +671,18 @@ " device tree !\n", tag); return -EINVAL; } + depth++; pathp = (char *)p; p = _ALIGN(p + strlen(pathp) + 1, 4); - rc = it(p, pathp, data); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); if (rc != 0) break; } while(1); @@ -689,17 +705,21 @@ const char *nstr; p += 4; + if (tag == OF_DT_NOP) + continue; if (tag != OF_DT_PROP) return NULL; sz = *((u32 *)p); noff = *((u32 *)(p + 4)); p += 8; - p = _ALIGN(p, sz >= 8 ? 8 : 4); + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); if (nstr == NULL) { - printk(KERN_WARNING "Can't find property index name !\n"); + printk(KERN_WARNING "Can't find property index" + " name !\n"); return NULL; } if (strcmp(name, nstr) == 0) { @@ -713,7 +733,7 @@ } static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, - unsigned long align) + unsigned long align) { void *res; @@ -727,13 +747,16 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, unsigned long *p, struct device_node *dad, - struct device_node ***allnextpp) + struct device_node ***allnextpp, + unsigned long fpsize) { struct device_node *np; struct property *pp, **prev_pp = NULL; char *pathp; u32 tag; - unsigned int l; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; tag = *((u32 *)(*p)); if (tag != OF_DT_BEGIN_NODE) { @@ -742,21 +765,62 @@ } *p += 4; pathp = (char *)*p; - l = strlen(pathp) + 1; + l = allocl = strlen(pathp) + 1; *p = _ALIGN(*p + l, 4); - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } else { + /* account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); if (allnextpp) { memset(np, 0, sizeof(*np)); np->full_name = ((char*)np) + sizeof(struct device_node); - memcpy(np->full_name, pathp, l); + if (new_format) { + char *p = np->full_name; + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(p, dad->full_name); +#ifdef DEBUG + if ((strlen(p) + l + 1) != allocl) { + DBG("%s: p: %d, l: %d, a: %d\n", + pathp, strlen(p), l, allocl); + } +#endif + p += strlen(p); + } + *(p++) = '/'; + memcpy(p, pathp, l); + } else + memcpy(np->full_name, pathp, l); prev_pp = &np->properties; **allnextpp = np; *allnextpp = &np->allnext; if (dad != NULL) { np->parent = dad; - /* we temporarily use the `next' field as `last_child'. */ + /* we temporarily use the next field as `last_child'*/ if (dad->next == 0) dad->child = np; else @@ -770,18 +834,26 @@ char *pname; tag = *((u32 *)(*p)); + if (tag == OF_DT_NOP) { + *p += 4; + continue; + } if (tag != OF_DT_PROP) break; *p += 4; sz = *((u32 *)(*p)); noff = *((u32 *)((*p) + 4)); - *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); + *p += 8; + if (initial_boot_params->version < 0x10) + *p = _ALIGN(*p, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); if (pname == NULL) { printk("Can't find property name in list !\n"); break; } + if (strcmp(pname, "name") == 0) + has_name = 1; l = strlen(pname) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); @@ -801,6 +873,36 @@ } *p = _ALIGN((*p) + sz, 4); } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + char *p = pathp, *ps = pathp, *pa = NULL; + int sz; + + while (*p) { + if ((*p) == '@') + pa = p; + if ((*p) == '/') + ps = p + 1; + p++; + } + if (pa < ps) + pa = p; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (allnextpp) { + pp->name = "name"; + pp->length = sz; + pp->value = (unsigned char *)(pp + 1); + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + DBG("fixed up name for %s -> %s\n", pathp, pp->value); + } + } if (allnextpp) { *prev_pp = NULL; np->name = get_property(np, "name", NULL); @@ -812,7 +914,7 @@ np->type = ""; } while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp); + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); tag = *((u32 *)(*p)); } if (tag != OF_DT_END_NODE) { @@ -842,21 +944,27 @@ /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - size = unflatten_dt_node(0, &start, NULL, NULL); + size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = (size | 3) + 1; DBG(" size is %lx, allocating...\n", size); /* Allocate memory for the expanded device tree */ - mem = (unsigned long)abs_to_virt(lmb_alloc(size, + mem = (unsigned long)abs_to_virt(lmb_alloc(size + 4, __alignof__(struct device_node))); + ((u32 *)mem)[size / 4] = 0xdeadbeef; + DBG(" unflattening...\n", mem); /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - unflatten_dt_node(mem, &start, NULL, &allnextp); + unflatten_dt_node(mem, &start, NULL, &allnextp, 0); if (*((u32 *)start) != OF_DT_END) - printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); + printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (((u32 *)mem)[size / 4] != 0xdeadbeef) + printk(KERN_WARNING "End of tree marker overwritten: %08x\n", + ((u32 *)mem)[size / 4] ); *allnextp = NULL; /* Get pointer to OF "/chosen" node for use everywhere */ @@ -880,7 +988,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { char *type = get_flat_dt_prop(node, "device_type", NULL); u32 *prop; @@ -933,13 +1041,15 @@ } static int __init early_init_dt_scan_chosen(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { u32 *prop; u64 *prop64; extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; - if (strcmp(full_path, "/chosen") != 0) + DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + + if (depth != 1 || strcmp(uname, "chosen") != 0) return 0; /* get platform type */ @@ -989,18 +1099,20 @@ } static int __init early_init_dt_scan_root(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { u32 *prop; - if (strcmp(full_path, "/") != 0) + if (depth != 0) return 0; prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); dt_root_size_cells = (prop == NULL) ? 1 : *prop; - + DBG("dt_root_size_cells = %x\n", dt_root_size_cells); + prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ return 1; @@ -1028,7 +1140,7 @@ static int __init early_init_dt_scan_memory(unsigned long node, - const char *full_path, void *data) + const char *uname, int depth, void *data) { char *type = get_flat_dt_prop(node, "device_type", NULL); cell_t *reg, *endp; @@ -1044,7 +1156,9 @@ endp = reg + (l / sizeof(cell_t)); - DBG("memory scan node %s ...\n", full_path); + DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n", + uname, l, reg[0], reg[1], reg[2], reg[3]); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { unsigned long base, size; @@ -1455,10 +1569,11 @@ struct device_node *np = allnodes; read_lock(&devtree_lock); - for (; np != 0; np = np->allnext) + for (; np != 0; np = np->allnext) { if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 && of_node_get(np)) break; + } read_unlock(&devtree_lock); return np; } Index: linux-work/include/asm-ppc64/prom.h =================================================================== --- linux-work.orig/include/asm-ppc64/prom.h 2005-06-02 08:05:58.000000000 +1000 +++ linux-work/include/asm-ppc64/prom.h 2005-06-03 16:58:01.000000000 +1000 @@ -22,13 +22,15 @@ #define RELOC(x) (*PTRRELOC(&(x))) /* Definitions used by the flattened device tree */ -#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ -#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ #define OF_DT_END_NODE 0x2 /* End node */ -#define OF_DT_PROP 0x3 /* Property: name off, size, content */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ #define OF_DT_END 0x9 -#define OF_DT_VERSION 1 +#define OF_DT_VERSION 0x10 /* * This is what gets passed to the kernel by prom_init or kexec @@ -54,7 +56,9 @@ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ /* version 2 fields below */ - u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ }; Index: linux-work/arch/ppc64/kernel/smp.c =================================================================== --- linux-work.orig/arch/ppc64/kernel/smp.c 2005-06-03 16:52:28.000000000 +1000 +++ linux-work/arch/ppc64/kernel/smp.c 2005-06-03 16:58:01.000000000 +1000 @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG +#define DEBUG #include #include From strosake at austin.ibm.com Fri Jun 3 13:44:48 2005 From: strosake at austin.ibm.com (Mike Strosaker) Date: Thu, 02 Jun 2005 22:44:48 -0500 Subject: [PATCH] correct printing to op panel In-Reply-To: <17052.58068.511994.89604@cargo.ozlabs.ibm.com> References: <429CDC42.30905@austin.ibm.com> <17052.58068.511994.89604@cargo.ozlabs.ibm.com> Message-ID: <429FD230.9040303@austin.ibm.com> Hi, Paul: Paul Mackerras wrote: > I want to think about this one a bit more. The ppc_md.progress() > calls aren't only used for the i/pSeries op panels, and I need to > think about the effect of \f on the other progress implementations. > It would be best, I think, if the outputting of \f could be done by > the pSeries progress function rather than the caller, if possible. It turns out that there's an ibm,form-feed property; this modified patch uses it in the pSeries-specific progress routine. This patch also checks the number of rows and the specific width of each row (the second row on power5 systems can actually hold 80 characters). If the displayed text is too wide for the physical display, it can be viewed in the ASM menus, or by selecting option 14 on the op panel. Signed-off-by: Mike Strosaker -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: oppanel.patch Url: http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050602/3f8a6213/attachment.txt From sfr at canb.auug.org.au Fri Jun 3 17:58:19 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Fri, 3 Jun 2005 17:58:19 +1000 Subject: [PATCH 0/10] ppc64 iSeries: header file cleanups Message-ID: <20050603175819.3d143a07.sfr@canb.auug.org.au> Hi Andrew, This set of patches does some long needed cleanup on the legacy iSeries header files. A lot of it is white space fixes and comment reformatting. Some is just simplification of code in inline functions and we actually get rid of 3 files. There are no StudleyCaps changes in here, that can wait until I have reduced the actual files to a minimum. arch/ppc64/kernel/HvLpEvent.c | 2 arch/ppc64/kernel/ItLpQueue.c | 1 arch/ppc64/kernel/asm-offsets.c | 1 arch/ppc64/kernel/iSeries_VpdInfo.c | 1 arch/ppc64/kernel/iSeries_pci.c | 2 arch/ppc64/kernel/iSeries_proc.c | 3 arch/ppc64/kernel/iSeries_setup.c | 6 arch/ppc64/kernel/iSeries_smp.c | 2 arch/ppc64/kernel/idle.c | 5 arch/ppc64/kernel/irq.c | 2 arch/ppc64/kernel/lparcfg.c | 2 arch/ppc64/kernel/mf.c | 1 arch/ppc64/kernel/ras.c | 1 arch/ppc64/kernel/rtc.c | 2 arch/ppc64/kernel/setup.c | 3 arch/ppc64/kernel/viopath.c | 10 include/asm-ppc64/iSeries/HvCall.h | 156 +------- include/asm-ppc64/iSeries/HvCallCfg.h | 213 ----------- include/asm-ppc64/iSeries/HvCallEvent.h | 94 +---- include/asm-ppc64/iSeries/HvCallHpt.h | 128 ++---- include/asm-ppc64/iSeries/HvCallPci.h | 486 +++++++++----------------- include/asm-ppc64/iSeries/HvCallSc.h | 40 +- include/asm-ppc64/iSeries/HvCallSm.h | 36 - include/asm-ppc64/iSeries/HvCallXm.h | 114 ++---- include/asm-ppc64/iSeries/HvLpConfig.h | 298 ++++----------- include/asm-ppc64/iSeries/HvLpEvent.h | 122 +++--- include/asm-ppc64/iSeries/HvReleaseData.h | 78 ++-- include/asm-ppc64/iSeries/HvTypes.h | 112 ++--- include/asm-ppc64/iSeries/IoHriMainStore.h | 33 - include/asm-ppc64/iSeries/IoHriProcessorVpd.h | 32 - include/asm-ppc64/iSeries/ItExtVpdPanel.h | 54 +- include/asm-ppc64/iSeries/ItIplParmsReal.h | 99 ++--- include/asm-ppc64/iSeries/ItLpNaca.h | 46 +- include/asm-ppc64/iSeries/ItLpQueue.h | 86 ++-- include/asm-ppc64/iSeries/ItLpRegSave.h | 41 +- include/asm-ppc64/iSeries/ItSpCommArea.h | 10 include/asm-ppc64/iSeries/ItVpdAreas.h | 135 +++---- include/asm-ppc64/iSeries/LparData.h | 49 -- include/asm-ppc64/iSeries/LparMap.h | 44 +- include/asm-ppc64/iSeries/XmPciLpEvent.h | 15 include/asm-ppc64/iSeries/iSeries_io.h | 59 +-- include/asm-ppc64/iSeries/iSeries_irq.h | 18 include/asm-ppc64/iSeries/iSeries_pci.h | 161 ++++---- include/asm-ppc64/iSeries/iSeries_proc.h | 24 - include/asm-ppc64/iSeries/mf.h | 5 include/asm-ppc64/iSeries/vio.h | 57 +-- include/asm-ppc64/paca.h | 2 47 files changed, 1018 insertions(+), 1873 deletions(-) -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ -------------- next part -------------- A non-text attachment was scrubbed... Name: 00000000.mimetmp Type: application/pgp-signature Size: 190 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050603/fcc8ad0c/attachment.pgp -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://ozlabs.org/pipermail/linuxppc64-dev/attachments/20050603/fcc8ad0c/attachment-0001.pgp From sfr at canb.auug.org.au Fri Jun 3 18:04:17 2005 From: sfr at canb.auug.org.au (Stephen Rothwell) Date: Fri, 3 Jun 2005 18:04:17 +1000 Subject: [PATCH 2/10] ppc64 iSeries: header file white space cleanups In-Reply-To: <20050603175819.3d143a07.sfr@canb.auug.org.au> References: <20050603175819.3d143a07.sfr@canb.auug.org.au> Message-ID: <20050603180417.4cfb2416.sfr@canb.auug.org.au> Hi Andrew, This patch just contains white space and comment cleanups in the iSeries headers files. There are no semantic changes. Signed-off-by: Stephen Rothwell -- Cheers, Stephen Rothwell sfr at canb.auug.org.au http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCall.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCall.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCall.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCall.h 2005-06-01 14:51:07.000000000 +1000 @@ -1,34 +1,28 @@ /* * HvCall.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -//=========================================================================== -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//=========================================================================== +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #ifndef _HVCALL_H #define _HVCALL_H -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include #include @@ -76,9 +70,9 @@ enum HvCall_VaryOffChunkRc */ /* Type of yield for HvCallBaseYieldProcessor */ -#define HvCall_YieldTimed 0 // Yield until specified time (tb) -#define HvCall_YieldToActive 1 // Yield until all active procs have run -#define HvCall_YieldToProc 2 // Yield until the specified processor has run +#define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ +#define HvCall_YieldToActive 1 /* Yield until all active procs have run */ +#define HvCall_YieldToProc 2 /* Yield until the specified processor has run */ /* interrupt masks for setEnabledInterrupts */ #define HvCall_MaskIPI 0x00000001 @@ -86,7 +80,7 @@ enum HvCall_VaryOffChunkRc #define HvCall_MaskLpProd 0x00000004 #define HvCall_MaskTimeout 0x00000008 -/* Log buffer formats */ +/* Log buffer formats */ #define HvCall_LogBuffer_ASCII 0 #define HvCall_LogBuffer_EBCDIC 1 @@ -95,7 +89,7 @@ enum HvCall_VaryOffChunkRc #define HvCallBaseGetHwPatch HvCallBase + 2 #define HvCallBaseReIplSpAttn HvCallBase + 3 #define HvCallBaseSetASR HvCallBase + 4 -#define HvCallBaseSetASRAndRfi HvCallBase + 5 +#define HvCallBaseSetASRAndRfi HvCallBase + 5 #define HvCallBaseSetIMR HvCallBase + 6 #define HvCallBaseSendIPI HvCallBase + 7 #define HvCallBaseTerminateMachine HvCallBase + 8 @@ -115,81 +109,75 @@ enum HvCall_VaryOffChunkRc #define HvCallBaseGetLogBufferCodePage HvCallBase + 22 #define HvCallBaseGetLogBufferFormat HvCallBase + 23 #define HvCallBaseGetLogBufferLength HvCallBase + 24 -#define HvCallBaseReadLogBuffer HvCallBase + 25 +#define HvCallBaseReadLogBuffer HvCallBase + 25 #define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26 -#define HvCallBaseWriteLogBuffer HvCallBase + 27 +#define HvCallBaseWriteLogBuffer HvCallBase + 27 #define HvCallBaseRouter28 HvCallBase + 28 #define HvCallBaseRouter29 HvCallBase + 29 #define HvCallBaseRouter30 HvCallBase + 30 -#define HvCallBaseSetDebugBus HvCallBase + 31 +#define HvCallBaseSetDebugBus HvCallBase + 31 -#define HvCallCcSetDABR HvCallCc + 7 +#define HvCallCcSetDABR HvCallCc + 7 -//===================================================================================== -static inline void HvCall_setVirtualDecr(void) +static inline void HvCall_setVirtualDecr(void) { - /* Ignore any error return codes - most likely means that the target value for the - * LP has been increased and this vary off would bring us below the new target. */ + /* + * Ignore any error return codes - most likely means that the + * target value for the LP has been increased and this vary off + * would bring us below the new target. + */ HvCall0(HvCallBaseSetVirtualDecr); } -//===================================================================== -static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) + +static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) { - HvCall2( HvCallBaseYieldProcessor, typeOfYield, yieldParm ); + HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm); } -//===================================================================== -static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) + +static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) { - HvCall1(HvCallBaseSetEnabledInterrupts,enabledInterrupts); + HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); } -//===================================================================== -static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) +static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) { - HvCall1(HvCallBaseClearLogBuffer,lpindex); + HvCall1(HvCallBaseClearLogBuffer, lpindex); } -//===================================================================== -static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) +static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) { - u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage,lpindex); + u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage, lpindex); return retVal; } -//===================================================================== -static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) +static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) { - int retVal = HvCall1(HvCallBaseGetLogBufferFormat,lpindex); + int retVal = HvCall1(HvCallBaseGetLogBufferFormat, lpindex); return retVal; } -//===================================================================== -static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) +static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) { - u32 retVal = HvCall1(HvCallBaseGetLogBufferLength,lpindex); + u32 retVal = HvCall1(HvCallBaseGetLogBufferLength, lpindex); return retVal; } -//===================================================================== -static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) +static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) { - HvCall2(HvCallBaseSetLogBufferFormatAndCodePage,format, codePage); + HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); } -//===================================================================== -int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); -void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); +extern int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); +extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); -//===================================================================== -static inline void HvCall_sendIPI(struct paca_struct * targetPaca) +static inline void HvCall_sendIPI(struct paca_struct *targetPaca) { - HvCall1( HvCallBaseSendIPI, targetPaca->paca_index ); + HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); } -//===================================================================== -static inline void HvCall_terminateMachineSrc(void) +static inline void HvCall_terminateMachineSrc(void) { - HvCall0( HvCallBaseTerminateMachineSrc ); + HvCall0(HvCallBaseTerminateMachineSrc); } static inline void HvCall_setDABR(unsigned long val) diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallCfg.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallCfg.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallCfg.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallCfg.h 2005-06-03 14:03:07.000000000 +1000 @@ -1,43 +1,32 @@ /* * HvCallCfg.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -//===================================================================================== -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//===================================================================================== +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #ifndef _HVCALLCFG_H #define _HVCALLCFG_H -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//------------------------------------------------------------------------------------- -// Constants -//------------------------------------------------------------------------------------- - -enum HvCallCfg_ReqQual -{ +enum HvCallCfg_ReqQual { HvCallCfg_Cur = 0, HvCallCfg_Init = 1, HvCallCfg_Max = 2, @@ -49,7 +38,7 @@ enum HvCallCfg_ReqQual #define HvCallCfgGetLpVrmIndex HvCallCfg + 2 #define HvCallCfgGetLpMinSupportedPlicVrmIndex HvCallCfg + 3 #define HvCallCfgGetLpMinCompatablePlicVrmIndex HvCallCfg + 4 -#define HvCallCfgGetLpVrmName HvCallCfg + 5 +#define HvCallCfgGetLpVrmName HvCallCfg + 5 #define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 #define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 #define HvCallCfgGetSystemMsChunks HvCallCfg + 8 @@ -76,108 +65,113 @@ enum HvCallCfg_ReqQual #define HvCallCfgSetMinRuntimeMsChunks HvCallCfg + 29 #define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 #define HvCallCfgGetLpExecutionMode HvCallCfg + 31 -#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 +#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 -//==================================================================== static inline HvLpIndex HvCallCfg_getLps(void) { HvLpIndex retVal = HvCall0(HvCallCfgGetLps); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline int HvCallCfg_isBusDedicated(u64 busIndex) + +static inline int HvCallCfg_isBusDedicated(u64 busIndex) { int retVal = HvCall1(HvCallCfgIsBusDedicated,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== + static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) { HvLpIndex retVal = HvCall1(HvCallCfgGetBusOwner,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) + +static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) { HvLpIndexMap retVal = HvCall1(HvCallCfgGetBusAllocation,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) + +static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) { HvLpIndexMap retVal = HvCall0(HvCallCfgGetActiveLpMap); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap(HvLpIndex lp) + +static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( + HvLpIndex lp) { - // This is a new function in V5R1 so calls to this on older - // hypervisors will return -1 + /* + * This is a new function in V5R1 so calls to this on older + * hypervisors will return -1 + */ u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); - if(retVal == -1) + if (retVal == -1) retVal = 0; // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getSystemMsChunks(void) + +static inline u64 HvCallCfg_getSystemMsChunks(void) { u64 retVal = HvCall0(HvCallCfgGetSystemMsChunks); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetMsChunks,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) + +static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) { - // NOTE: This function was added in v5r1 so older hypervisors will return a -1 value - u64 retVal = HvCall1(HvCallCfgGetMinRuntimeMsChunks,lp); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + /* + * NOTE: This function was added in v5r1 so older hypervisors + * will return a -1 value + */ + return HvCall1(HvCallCfgGetMinRuntimeMsChunks, lp); } -//=================================================================== -static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) + +static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) { u64 retVal = HvCall1(HvCallCfgSetMinRuntimeMsChunks,chunks); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) + +static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) { u64 retVal = HvCall0(HvCallCfgGetSystemPhysicalProcessors); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetPhysicalProcessors,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, - u16 hvLogicalProcIndex) + +static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, + u16 hvLogicalProcIndex) { u64 retVal = HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc,lp,hvLogicalProcIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== -static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) + +static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) { HvLpSharedPoolIndex retVal = HvCall1(HvCallCfgGetSharedPoolIndex,lp); @@ -185,29 +179,29 @@ static inline HvLpSharedPoolIndex HvCall return retVal; } -//================================================================== -static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetSharedProcUnits,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== -static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) + +static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool,sPI); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== + static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) { u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex,lp); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; - } #endif /* _HVCALLCFG_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallEvent.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallEvent.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallEvent.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallEvent.h 2005-06-03 14:04:46.000000000 +1000 @@ -1,32 +1,28 @@ /* * HvCallEvent.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. */ #ifndef _HVCALLEVENT_H #define _HVCALLEVENT_H -/* - * Standard Includes - */ #include #include #include @@ -71,7 +67,7 @@ typedef u64 HvLpDma_Rc; #define HvCallEventCloseLpEventPath HvCallEvent + 2 #define HvCallEventDmaBufList HvCallEvent + 3 #define HvCallEventDmaSingle HvCallEvent + 4 -#define HvCallEventDmaToSp HvCallEvent + 5 +#define HvCallEventDmaToSp HvCallEvent + 5 #define HvCallEventGetOverflowLpEvents HvCallEvent + 6 #define HvCallEventGetSourceLpInstanceId HvCallEvent + 7 #define HvCallEventGetTargetLpInstanceId HvCallEvent + 8 @@ -85,13 +81,13 @@ typedef u64 HvLpDma_Rc; static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) { - HvCall1(HvCallEventGetOverflowLpEvents,queueIndex); + HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) { - HvCall1(HvCallEventSetInterLpQueueIndex,queueIndex); + HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } @@ -138,7 +134,7 @@ static inline HvLpEvent_Rc HvCallEvent_s { HvLpEvent_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedParms parms; u64 dword; @@ -225,7 +221,7 @@ static inline HvLpDma_Rc HvCallEvent_dma u64 localBufList, u64 remoteBufList, u32 transferLength) { HvLpDma_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; u64 dword; @@ -257,7 +253,7 @@ static inline HvLpDma_Rc HvCallEvent_dma u64 localAddrOrTce, u64 remoteAddrOrTce, u32 transferLength) { HvLpDma_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; u64 dword; @@ -280,7 +276,7 @@ static inline HvLpDma_Rc HvCallEvent_dma return retVal; } -static inline HvLpDma_Rc HvCallEvent_dmaToSp(void* local, u32 remote, +static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, u32 length, HvLpDma_Direction dir) { u64 abs_addr; @@ -293,5 +289,4 @@ static inline HvLpDma_Rc HvCallEvent_dma return retVal; } - #endif /* _HVCALLEVENT_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallHpt.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallHpt.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallHpt.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallHpt.h 2005-06-03 14:06:15.000000000 +1000 @@ -1,17 +1,17 @@ /* * HvCallHpt.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,21 +19,15 @@ #ifndef _HVCALLHPT_H #define _HVCALLHPT_H -//============================================================================ -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #include #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallHptGetHptAddress HvCallHpt + 0 #define HvCallHptGetHptPages HvCallHpt + 1 #define HvCallHptSetPp HvCallHpt + 5 @@ -47,81 +41,76 @@ #define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 -//============================================================================ -static inline u64 HvCallHpt_getHptAddress(void) +static inline u64 HvCallHpt_getHptAddress(void) { u64 retval = HvCall0(HvCallHptGetHptAddress); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================ -static inline u64 HvCallHpt_getHptPages(void) -{ + +static inline u64 HvCallHpt_getHptPages(void) +{ u64 retval = HvCall0(HvCallHptGetHptPages); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================= -static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) + +static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) { - HvCall2( HvCallHptSetPp, hpteIndex, value ); + HvCall2(HvCallHptSetPp, hpteIndex, value); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff ) + +static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) { - HvCall3( HvCallHptSetSwBits, hpteIndex, bitson, bitsoff ); + HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) - + +static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) { - HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex ); + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, u8 bitsoff ) - + +static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, + u8 bitsoff) { u64 compressedStatus; - compressedStatus = HvCall4( HvCallHptInvalidateSetSwBitsGet, hpteIndex, bitson, bitsoff, 1 ); - HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex ); + + compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, + hpteIndex, bitson, bitsoff, 1); + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return compressedStatus; } -//============================================================================= -static inline u64 HvCallHpt_findValid( HPTE *hpte, u64 vpn ) + +static inline u64 HvCallHpt_findValid(HPTE *hpte, u64 vpn) { u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retIndex; } -//============================================================================= -static inline u64 HvCallHpt_findNextValid( HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff ) + +static inline u64 HvCallHpt_findNextValid(HPTE *hpte, u32 hpteIndex, + u8 bitson, u8 bitsoff) { u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retIndex; } -//============================================================================= -static inline void HvCallHpt_get( HPTE *hpte, u32 hpteIndex ) + +static inline void HvCallHpt_get(HPTE *hpte, u32 hpteIndex) { - HvCall2Ret16( HvCallHptGet, hpte, hpteIndex, 0 ); + HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================ -static inline void HvCallHpt_addValidate( u32 hpteIndex, - u32 hBit, - HPTE *hpte ) - + +static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, HPTE *hpte) { - HvCall4( HvCallHptAddValidate, hpteIndex, - hBit, (*((u64 *)hpte)), (*(((u64 *)hpte)+1)) ); + HvCall4(HvCallHptAddValidate, hpteIndex, hBit, (*((u64 *)hpte)), + (*(((u64 *)hpte)+1))); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } - -//============================================================================= - #endif /* _HVCALLHPT_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallPci.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallPci.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallPci.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallPci.h 2005-06-03 14:10:49.000000000 +1000 @@ -1,26 +1,26 @@ -/************************************************************************/ -/* Provides the Hypervisor PCI calls for iSeries Linux Parition. */ -/* Copyright (C) 2001 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the: */ -/* Free Software Foundation, Inc., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created, Jan 9, 2001 */ -/************************************************************************/ +/* + * Provides the Hypervisor PCI calls for iSeries Linux Parition. + * Copyright (C) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, Jan 9, 2001 + */ #ifndef _HVCALLPCI_H #define _HVCALLPCI_H @@ -34,8 +34,8 @@ */ struct HvCallPci_DsaAddr { u16 busNumber; /* PHB index? */ - u8 subBusNumber; /* PCI bus number? */ - u8 deviceId; /* device and function? */ + u8 subBusNumber; /* PCI bus number? */ + u8 deviceId; /* device and function? */ u8 barNumber; u8 reserved[3]; }; @@ -52,34 +52,37 @@ struct HvCallPci_LoadReturn { enum HvCallPci_DeviceType { HvCallPci_NodeDevice = 1, - HvCallPci_SpDevice = 2, - HvCallPci_IopDevice = 3, - HvCallPci_BridgeDevice = 4, - HvCallPci_MultiFunctionDevice = 5, - HvCallPci_IoaDevice = 6 + HvCallPci_SpDevice = 2, + HvCallPci_IopDevice = 3, + HvCallPci_BridgeDevice = 4, + HvCallPci_MultiFunctionDevice = 5, + HvCallPci_IoaDevice = 6 }; struct HvCallPci_DeviceInfo { - u32 deviceType; // See DeviceType enum for values + u32 deviceType; /* See DeviceType enum for values */ }; - + struct HvCallPci_BusUnitInfo { - u32 sizeReturned; // length of data returned - u32 deviceType; // see DeviceType enum for values + u32 sizeReturned; /* length of data returned */ + u32 deviceType; /* see DeviceType enum for values */ }; struct HvCallPci_BridgeInfo { - struct HvCallPci_BusUnitInfo busUnitInfo; // Generic bus unit info - u8 subBusNumber; // Bus number of secondary bus - u8 maxAgents; // Max idsels on secondary bus - u8 maxSubBusNumber; // Max Sub Bus - u8 logicalSlotNumber; // Logical Slot Number for IOA + struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */ + u8 subBusNumber; /* Bus number of secondary bus */ + u8 maxAgents; /* Max idsels on secondary bus */ + u8 maxSubBusNumber; /* Max Sub Bus */ + u8 logicalSlotNumber; /* Logical Slot Number for IOA */ }; - -// Maximum BusUnitInfo buffer size. Provided for clients so they can allocate -// a buffer big enough for any type of bus unit. Increase as needed. + +/* + * Maximum BusUnitInfo buffer size. Provided for clients so + * they can allocate a buffer big enough for any type of bus + * unit. Increase as needed. + */ enum {HvCallPci_MaxBusUnitInfoSize = 128}; struct HvCallPci_BarParms { @@ -89,12 +92,12 @@ struct HvCallPci_BarParms { u64 protectStart; u64 protectEnd; u64 relocationOffset; - u64 pciAddress; + u64 pciAddress; u64 reserved[3]; -}; +}; enum HvCallPci_VpdType { - HvCallPci_BusVpd = 1, + HvCallPci_BusVpd = 1, HvCallPci_BusAdapterVpd = 2 }; @@ -123,15 +126,13 @@ enum HvCallPci_VpdType { #define HvCallPciUnmaskInterrupts HvCallPci + 49 #define HvCallPciGetBusUnitInfo HvCallPci + 50 -//============================================================================ static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u8 *value) + u8 deviceId, u32 offset, u8 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -145,15 +146,14 @@ static inline u64 HvCallPci_configLoad8( return retVal.rc; } -//============================================================================ + static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u16 *value) + u8 deviceId, u32 offset, u16 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -167,15 +167,14 @@ static inline u64 HvCallPci_configLoad16 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u32 *value) + +static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u32 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -189,15 +188,14 @@ static inline u64 HvCallPci_configLoad32 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u8 value) + +static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u8 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -209,15 +207,14 @@ static inline u64 HvCallPci_configStore8 return retVal; } -//============================================================================ -static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u16 value) + +static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u16 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -229,15 +226,14 @@ static inline u64 HvCallPci_configStore1 return retVal; } -//============================================================================ -static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u32 value) + +static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u32 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -249,18 +245,15 @@ static inline u64 HvCallPci_configStore3 return retVal; } -//============================================================================ -static inline u64 HvCallPci_barLoad8(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u8* valueParm) + +static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u8 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -275,18 +268,15 @@ static inline u64 HvCallPci_barLoad8(u16 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad16(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u16* valueParm) + +static inline u64 HvCallPci_barLoad16(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u16 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -301,18 +291,15 @@ static inline u64 HvCallPci_barLoad16(u1 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad32(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u32* valueParm) + +static inline u64 HvCallPci_barLoad32(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u32 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -327,18 +314,15 @@ static inline u64 HvCallPci_barLoad32(u1 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad64(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u64* valueParm) + +static inline u64 HvCallPci_barLoad64(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u64 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -353,19 +337,16 @@ static inline u64 HvCallPci_barLoad64(u1 return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barStore8(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u8 valueParm) + +static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u8 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -377,19 +358,16 @@ static inline u64 HvCallPci_barStore8(u1 return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore16(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u16 valueParm) + +static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u16 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -401,19 +379,16 @@ static inline u64 HvCallPci_barStore16(u return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore32(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u32 valueParm) + +static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u32 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -425,19 +400,16 @@ static inline u64 HvCallPci_barStore32(u return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore64(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u64 valueParm) + +static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u64 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -449,10 +421,9 @@ static inline u64 HvCallPci_barStore64(u return retVal; } -//============================================================================ -static inline u64 HvCallPci_eoi(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm) + +static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; @@ -469,13 +440,9 @@ static inline u64 HvCallPci_eoi(u16 busN return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_getBarParms(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 parms, - u32 sizeofParms) + +static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -493,16 +460,14 @@ static inline u64 HvCallPci_getBarParms( return retVal; } -//============================================================================ -static inline u64 HvCallPci_maskFisr(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 fisrMask) + +static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -514,16 +479,14 @@ static inline u64 HvCallPci_maskFisr(u16 return retVal; } -//============================================================================ -static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 fisrMask) + +static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -535,11 +498,9 @@ static inline u64 HvCallPci_unmaskFisr(u return retVal; } -//============================================================================ -static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 onNotOff) + +static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 onNotOff) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -556,12 +517,9 @@ static inline u64 HvCallPci_setSlotReset return retVal; } -//============================================================================ -static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, - u8 subBusParm, - u8 deviceNumberParm, - u64 parms, - u32 sizeofParms) + +static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -578,16 +536,14 @@ static inline u64 HvCallPci_getDeviceInf return retVal; } -//============================================================================ -static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 interruptMask) + +static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -599,16 +555,14 @@ static inline u64 HvCallPci_maskInterrup return retVal; } -//============================================================================ -static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 interruptMask) + +static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -620,18 +574,14 @@ static inline u64 HvCallPci_unmaskInterr return retVal; } -//============================================================================ -static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 parms, - u32 sizeofParms) +static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -643,9 +593,9 @@ static inline u64 HvCallPci_getBusUnitIn return retVal; } -//============================================================================ -static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm) +static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, + u16 sizeParm) { int xRetSize; u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusVpd); @@ -656,9 +606,9 @@ static inline int HvCallPci_getBusVpd(u1 xRetSize = xRc & 0xFFFF; return xRetSize; } -//============================================================================ -static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 sizeParm) +static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, + u16 sizeParm) { int xRetSize; u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusAdapterVpd); @@ -669,5 +619,5 @@ static inline int HvCallPci_getBusAdapte xRetSize = xRc & 0xFFFF; return xRetSize; } -//============================================================================ + #endif /* _HVCALLPCI_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallSc.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallSc.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallSc.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallSc.h 2005-06-01 15:46:19.000000000 +1000 @@ -1,17 +1,17 @@ /* * HvCallSc.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -30,22 +30,22 @@ #define HvCallSm 0x8007000000000000ul #define HvCallXm 0x8009000000000000ul -u64 HvCall0( u64 ); -u64 HvCall1( u64, u64 ); -u64 HvCall2( u64, u64, u64 ); -u64 HvCall3( u64, u64, u64, u64 ); -u64 HvCall4( u64, u64, u64, u64, u64 ); -u64 HvCall5( u64, u64, u64, u64, u64, u64 ); -u64 HvCall6( u64, u64, u64, u64, u64, u64, u64 ); -u64 HvCall7( u64, u64, u64, u64, u64, u64, u64, u64 ); +u64 HvCall0(u64); +u64 HvCall1(u64, u64); +u64 HvCall2(u64, u64, u64); +u64 HvCall3(u64, u64, u64, u64); +u64 HvCall4(u64, u64, u64, u64, u64); +u64 HvCall5(u64, u64, u64, u64, u64, u64); +u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); +u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); -u64 HvCall0Ret16( u64, void * ); -u64 HvCall1Ret16( u64, void *, u64 ); -u64 HvCall2Ret16( u64, void *, u64, u64 ); -u64 HvCall3Ret16( u64, void *, u64, u64, u64 ); -u64 HvCall4Ret16( u64, void *, u64, u64, u64, u64 ); -u64 HvCall5Ret16( u64, void *, u64, u64, u64, u64, u64 ); -u64 HvCall6Ret16( u64, void *, u64, u64, u64, u64, u64, u64 ); -u64 HvCall7Ret16( u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64 ); +u64 HvCall0Ret16(u64, void *); +u64 HvCall1Ret16(u64, void *, u64); +u64 HvCall2Ret16(u64, void *, u64, u64); +u64 HvCall3Ret16(u64, void *, u64, u64, u64); +u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); +u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); +u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); +u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); #endif /* _HVCALLSC_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallSm.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallSm.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallSm.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallSm.h 2005-06-03 14:12:36.000000000 +1000 @@ -1,17 +1,17 @@ /* * HvCallSm.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,34 +19,23 @@ #ifndef _HVCALLSM_H #define _HVCALLSM_H -//============================================================================ -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallSmGet64BitsOfAccessMap HvCallSm + 11 - -//============================================================================ -static inline u64 HvCallSm_get64BitsOfAccessMap( - HvLpIndex lpIndex, u64 indexIntoBitMap ) +static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, + u64 indexIntoBitMap) { u64 retval = HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================ + #endif /* _HVCALLSM_H */ diff -ruNp linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallXm.h linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallXm.h --- linus-iSeries-headers.1/include/asm-ppc64/iSeries/HvCallXm.h 2005-05-20 09:05:55.000000000 +1000 +++ linus-iSeries-headers.2/include/asm-ppc64/iSeries/HvCallXm.h 2005-06-03 14:17:07.000000000 +1000 @@ -1,30 +1,13 @@ -//============================================================================ -// Header File Id -// Name______________: HvCallXm.H -// -// Description_______: -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from SLIC. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from SLIC. + */ #ifndef _HVCALLXM_H #define _HVCALLXM_H -//------------------------------------------------------------------- -// Forward declarations -//------------------------------------------------------------------- - -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallXmGetTceTableParms HvCallXm + 0 #define HvCallXmTestBus HvCallXm + 1 #define HvCallXmConnectBusUnit HvCallXm + 2 @@ -33,47 +16,46 @@ #define HvCallXmSetTce HvCallXm + 11 #define HvCallXmSetTces HvCallXm + 13 - - -//============================================================================ -static inline void HvCallXm_getTceTableParms(u64 cb) +static inline void HvCallXm_getTceTableParms(u64 cb) { HvCall1(HvCallXmGetTceTableParms, cb); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================ -static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) -{ + +static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) +{ u64 retval = HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce ); // getPaca()->adjustHmtForNoO